diff options
| author | thegeorg <[email protected]> | 2023-10-03 11:19:48 +0300 | 
|---|---|---|
| committer | thegeorg <[email protected]> | 2023-10-03 11:43:28 +0300 | 
| commit | cda0c13f23f6b169fb0a49dc504b40a0aaecea09 (patch) | |
| tree | 26476e92e5af2c856e017afb1df8f8dff42495bf /contrib/tools/swig/Source/Modules | |
| parent | 4854116da9c5e3c95bb8440f2ea997c54b6e1a61 (diff) | |
Move contrib/tools/jdk to build/platform/java/jdk/testing
Diffstat (limited to 'contrib/tools/swig/Source/Modules')
32 files changed, 61951 insertions, 0 deletions
diff --git a/contrib/tools/swig/Source/Modules/README b/contrib/tools/swig/Source/Modules/README new file mode 100644 index 00000000000..058779d227d --- /dev/null +++ b/contrib/tools/swig/Source/Modules/README @@ -0,0 +1,9 @@ +06/25/2002 + +This directory contains all of the SWIG language modules.  Many of these +modules contain code that dates back to SWIG1.0.  The module API has changed +a lot in the development releases so this is fairly messy.  We're working on +cleaning it up, but you'll have to bear with us until it's done. + +-- Dave + diff --git a/contrib/tools/swig/Source/Modules/allocate.cxx b/contrib/tools/swig/Source/Modules/allocate.cxx new file mode 100644 index 00000000000..0e1262f8390 --- /dev/null +++ b/contrib/tools/swig/Source/Modules/allocate.cxx @@ -0,0 +1,971 @@ +/* -----------------------------------------------------------------------------  + * This file is part of SWIG, which is licensed as a whole under version 3  + * (or any later version) of the GNU General Public License. Some additional + * terms also apply to certain portions of SWIG. The full details of the SWIG + * license and copyrights can be found in the LICENSE and COPYRIGHT files + * included with the SWIG source code as distributed by the SWIG developers + * and at https://www.swig.org/legal.html. + * + * allocate.cxx + * + * This module tries to figure out which classes and structures support + * default constructors and destructors in C++.   There are several rules that + * define this behavior including pure abstract methods, private sections, + * and non-default constructors in base classes.  See the ARM or + * Doc/Manual/SWIGPlus.html for details. + * ----------------------------------------------------------------------------- */ + +#include "swigmod.h" +#include "cparse.h" + +static int virtual_elimination_mode = 0;	/* set to 0 on default */ + +/* Set virtual_elimination_mode */ +void Wrapper_virtual_elimination_mode_set(int flag) { +  virtual_elimination_mode = flag; +} + +/* Helper function to assist with abstract class checking.   +   This is a major hack. Sorry.  */ + +extern "C" { +  static String *search_decl = 0;	/* Declarator being searched */ +  static int check_implemented(Node *n) { +    String *decl; +    if (!n) +       return 0; +    while (n) { +      if (Strcmp(nodeType(n), "cdecl") == 0) { +	decl = Getattr(n, "decl"); +	if (SwigType_isfunction(decl)) { +	  SwigType *decl1 = SwigType_typedef_resolve_all(decl); +	  SwigType *decl2 = SwigType_pop_function(decl1); +	  if (Strcmp(decl2, search_decl) == 0) { +	    if (!GetFlag(n, "abstract")) { +	      Delete(decl1); +	      Delete(decl2); +	      return 1; +	    } +	  } +	  Delete(decl1); +	  Delete(decl2); +	} +      } +      n = Getattr(n, "csym:nextSibling"); +    } +    return 0; +  } +} + +class Allocate:public Dispatcher { +  Node *inclass; +  int extendmode; + +  /* Checks if a function, n, is the same as any in the base class, ie if the method is polymorphic. +   * Also checks for methods which will be hidden (ie a base has an identical non-virtual method). +   * Both methods must have public access for a match to occur. */ +  int function_is_defined_in_bases(Node *n, Node *bases) { + +    if (!bases) +      return 0; + +    String *this_decl = Getattr(n, "decl"); +    if (!this_decl) +       return 0; + +    String *name = Getattr(n, "name"); +    String *this_type = Getattr(n, "type"); +    String *resolved_decl = SwigType_typedef_resolve_all(this_decl); + +    // Search all base classes for methods with same signature +    for (int i = 0; i < Len(bases); i++) { +      Node *b = Getitem(bases, i); +      Node *base = firstChild(b); +      while (base) { +	if (Strcmp(nodeType(base), "extend") == 0) { +	  // Loop through all the %extend methods +	  Node *extend = firstChild(base); +	  while (extend) { +	    if (function_is_defined_in_bases_seek(n, b, extend, this_decl, name, this_type, resolved_decl)) { +	      Delete(resolved_decl); +	      return 1; +	    } +	    extend = nextSibling(extend); +	  } +	} else if (Strcmp(nodeType(base), "using") == 0) { +	  // Loop through all the using declaration methods +	  Node *usingdecl = firstChild(base); +	  while (usingdecl) { +	    if (function_is_defined_in_bases_seek(n, b, usingdecl, this_decl, name, this_type, resolved_decl)) { +	      Delete(resolved_decl); +	      return 1; +	    } +	    usingdecl = nextSibling(usingdecl); +	  } +	} else { +	  // normal methods +	  if (function_is_defined_in_bases_seek(n, b, base, this_decl, name, this_type, resolved_decl)) { +	    Delete(resolved_decl); +	    return 1; +	  } +	} +	base = nextSibling(base); +      } +    } +    Delete(resolved_decl); +    resolved_decl = 0; +    for (int j = 0; j < Len(bases); j++) { +      Node *b = Getitem(bases, j); +      if (function_is_defined_in_bases(n, Getattr(b, "allbases"))) +	return 1; +    } +    return 0; +  } + +  /* Helper function for function_is_defined_in_bases */ +  int function_is_defined_in_bases_seek(Node *n, Node *b, Node *base, String *this_decl, String *name, String *this_type, String *resolved_decl) { + +    String *base_decl = Getattr(base, "decl"); +    SwigType *base_type = Getattr(base, "type"); +    if (base_decl && base_type) { +      if (checkAttribute(base, "name", name) && !GetFlag(b, "feature:ignore") /* whole class is ignored */ ) { +	if (SwigType_isfunction(resolved_decl) && SwigType_isfunction(base_decl)) { +	  // We have found a method that has the same name as one in a base class +	  bool covariant_returntype = false; +	  bool returntype_match = Strcmp(base_type, this_type) == 0 ? true : false; +	  bool decl_match = Strcmp(base_decl, this_decl) == 0 ? true : false; +	  if (returntype_match && decl_match) { +	    // Exact match - we have found a method with identical signature +	    // No typedef resolution was done, but skipping it speeds things up slightly +	  } else { +	    // Either we have: +	    //  1) matching methods but are one of them uses a different typedef (return type or parameter) to the one in base class' method +	    //  2) matching polymorphic methods with covariant return type +	    //  3) a non-matching method (ie an overloaded method of some sort) +	    //  4) a matching method which is not polymorphic, ie it hides the base class' method + +	    // Check if fully resolved return types match (including +	    // covariant return types) +	    if (!returntype_match) { +	      String *this_returntype = function_return_type(n); +	      String *base_returntype = function_return_type(base); +	      returntype_match = Strcmp(this_returntype, base_returntype) == 0 ? true : false; +	      if (!returntype_match) { +		covariant_returntype = SwigType_issubtype(this_returntype, base_returntype) ? true : false; +		returntype_match = covariant_returntype; +	      } +	      Delete(this_returntype); +	      Delete(base_returntype); +	    } +	    // The return types must match at this point, for the whole method to match +	    if (returntype_match && !decl_match) { +	      // Now need to check the parameter list +	      // First do an inexpensive parameter count +	      ParmList *this_parms = Getattr(n, "parms"); +	      ParmList *base_parms = Getattr(base, "parms"); +	      if (ParmList_len(this_parms) == ParmList_len(base_parms)) { +		// Number of parameters are the same, now check that all the parameters match +		SwigType *base_fn = NewString(""); +		SwigType *this_fn = NewString(""); +		SwigType_add_function(base_fn, base_parms); +		SwigType_add_function(this_fn, this_parms); +		base_fn = SwigType_typedef_resolve_all(base_fn); +		this_fn = SwigType_typedef_resolve_all(this_fn); +		if (Strcmp(base_fn, this_fn) == 0) { +		  // Finally check that the qualifiers match +		  int base_qualifier = SwigType_isqualifier(resolved_decl); +		  int this_qualifier = SwigType_isqualifier(base_decl); +		  if (base_qualifier == this_qualifier) { +		    decl_match = true; +		  } +		} +		Delete(base_fn); +		Delete(this_fn); +	      } +	    } +	  } +	  //Printf(stderr,"look %s %s %d %d\n",base_decl, this_decl, returntype_match, decl_match); + +	  if (decl_match && returntype_match) { +	    // Found an identical method in the base class +	    bool this_wrapping_protected_members = is_member_director(n) ? true : false;	// This should really check for dirprot rather than just being a director method +	    bool base_wrapping_protected_members = is_member_director(base) ? true : false;	// This should really check for dirprot rather than just being a director method +	    bool both_have_public_access = is_public(n) && is_public(base); +	    bool both_have_protected_access = (is_protected(n) && this_wrapping_protected_members) && (is_protected(base) && base_wrapping_protected_members); +	    bool both_have_private_access = is_private(n) && is_private(base); +	    if (checkAttribute(base, "storage", "virtual")) { +	      // Found a polymorphic method. +	      // Mark the polymorphic method, in case the virtual keyword was not used. +	      Setattr(n, "storage", "virtual"); +	      if (!GetFlag(b, "feature:interface")) { // interface implementation neither hides nor overrides +		if (both_have_public_access || both_have_protected_access) { +		  if (!is_non_public_base(inclass, b)) +		    Setattr(n, "override", base);	// Note C# definition of override, ie access must be the same +		} +		else if (!both_have_private_access) { +		  // Different access +		  if (this_wrapping_protected_members || base_wrapping_protected_members) +		    if (!is_non_public_base(inclass, b)) +		      Setattr(n, "hides", base);	// Note C# definition of hiding, ie hidden if access is different +		} +	      } +	      // Try and find the most base's covariant return type +	      SwigType *most_base_covariant_type = Getattr(base, "covariant"); +	      if (!most_base_covariant_type && covariant_returntype) +		most_base_covariant_type = function_return_type(base, false); + +	      if (!most_base_covariant_type) { +		// Eliminate the derived virtual method. +		if (virtual_elimination_mode && !is_member_director(n)) +		  if (both_have_public_access) +		    if (!is_non_public_base(inclass, b)) +		      if (!Swig_symbol_isoverloaded(n)) { +			// Don't eliminate if an overloaded method as this hides the method +			// in the scripting languages: the dispatch function will hide the base method if ignored. +			SetFlag(n, "feature:ignore"); +		      } +	      } else { +		// Some languages need to know about covariant return types +		Setattr(n, "covariant", most_base_covariant_type); +	      } + +	    } else { +	      // Found an identical method in the base class, but it is not polymorphic. +	      if (both_have_public_access || both_have_protected_access) +		if (!is_non_public_base(inclass, b)) +		  Setattr(n, "hides", base); +	    } +	    if (both_have_public_access || both_have_protected_access) +	      return 1; +	  } +	} +      } +    } +    return 0; +  } + +  /* Determines whether the base class, b, is in the list of private +   * or protected base classes for class n. */ +  bool is_non_public_base(Node *n, Node *b) { +    bool non_public_base = false; +    Node *bases = Getattr(n, "privatebases"); +    if (bases) { +      for (int i = 0; i < Len(bases); i++) { +	Node *base = Getitem(bases, i); +	if (base == b) +	  non_public_base = true; +      } +    } +    bases = Getattr(n, "protectedbases"); +    if (bases) { +      for (int i = 0; i < Len(bases); i++) { +	Node *base = Getitem(bases, i); +	if (base == b) +	  non_public_base = true; +      } +    } +    return non_public_base; +  } + +  /* Returns the return type for a function. The node n should be a function. +     If resolve is true the fully returned type is fully resolved. +     Caller is responsible for deleting returned string. */ +  String *function_return_type(Node *n, bool resolve = true) { +    String *decl = Getattr(n, "decl"); +    SwigType *type = Getattr(n, "type"); +    String *ty = NewString(type); +    SwigType_push(ty, decl); +    if (SwigType_isqualifier(ty)) +      Delete(SwigType_pop(ty)); +    Delete(SwigType_pop_function(ty)); +    if (resolve) { +      String *unresolved = ty; +      ty = SwigType_typedef_resolve_all(unresolved); +      Delete(unresolved); +    } +    return ty; +  } + +  /* Checks if a class member is the same as inherited from the class bases */ +  int class_member_is_defined_in_bases(Node *member, Node *classnode) { +    Node *bases;		/* bases is the closest ancestors of classnode */ +    int defined = 0; + +    bases = Getattr(classnode, "allbases"); +    if (!bases) +      return 0; + +    { +      int old_mode = virtual_elimination_mode; +      if (is_member_director(classnode, member)) +	virtual_elimination_mode = 0; + +      if (function_is_defined_in_bases(member, bases)) { +	defined = 1; +      } + +      virtual_elimination_mode = old_mode; +    } + +    if (defined) +      return 1; +    else +      return 0; +  } + +  /* Checks to see if a class is abstract through inheritance, +     and saves the first node that seems to be abstract. +   */ +  int is_abstract_inherit(Node *n, Node *base = 0, int first = 0) { +    if (!first && (base == n)) +      return 0; +    if (!base) { +      /* Root node */ +      Symtab *stab = Getattr(n, "symtab");	/* Get symbol table for node */ +      Symtab *oldtab = Swig_symbol_setscope(stab); +      int ret = is_abstract_inherit(n, n, 1); +      Swig_symbol_setscope(oldtab); +      return ret; +    } +    List *abstracts = Getattr(base, "abstracts"); +    if (abstracts) { +      int dabstract = 0; +      int len = Len(abstracts); +      for (int i = 0; i < len; i++) { +	Node *nn = Getitem(abstracts, i); +	String *name = Getattr(nn, "name"); +	if (!name) +	  continue; +	if (Strchr(name, '~')) +	  continue;		/* Don't care about destructors */ +	String *base_decl = Getattr(nn, "decl"); +	if (base_decl) +	  base_decl = SwigType_typedef_resolve_all(base_decl); +	if (SwigType_isfunction(base_decl)) +	  search_decl = SwigType_pop_function(base_decl); +	Node *dn = Swig_symbol_clookup_local_check(name, 0, check_implemented); +	Delete(search_decl); +	Delete(base_decl); + +	if (!dn) { +	  List *nabstracts = Getattr(n, "abstracts"); +	  if (!nabstracts) { +	    nabstracts = NewList(); +	    Setattr(n, "abstracts", nabstracts); +	    Delete(nabstracts); +	  } +	  Append(nabstracts, nn); +	  if (!Getattr(n, "abstracts:firstnode")) { +	    Setattr(n, "abstracts:firstnode", nn); +	  } +	  dabstract = base != n; +	} +      } +      if (dabstract) +	return 1; +    } +    List *bases = Getattr(base, "allbases"); +    if (!bases) +      return 0; +    for (int i = 0; i < Len(bases); i++) { +      if (is_abstract_inherit(n, Getitem(bases, i))) { +	return 1; +      } +    } +    return 0; +  } + + +  /* Grab methods used by smart pointers */ + +  List *smart_pointer_methods(Node *cls, List *methods, int isconst, String *classname = 0) { +    if (!methods) { +      methods = NewList(); +    } + +    Node *c = firstChild(cls); + +    while (c) { +      if (Getattr(c, "error") || GetFlag(c, "feature:ignore")) { +	c = nextSibling(c); +	continue; +      } +      if (!isconst && (Strcmp(nodeType(c), "extend") == 0)) { +	methods = smart_pointer_methods(c, methods, isconst, Getattr(cls, "name")); +      } else if (Strcmp(nodeType(c), "cdecl") == 0) { +	if (!GetFlag(c, "feature:ignore")) { +	  String *storage = Getattr(c, "storage"); +	  if (!((Cmp(storage, "typedef") == 0)) +	      && !((Cmp(storage, "friend") == 0))) { +	    String *name = Getattr(c, "name"); +	    String *symname = Getattr(c, "sym:name"); +	    Node *e = Swig_symbol_clookup_local(name, 0); +	    if (e && is_public(e) && !GetFlag(e, "feature:ignore") && (Cmp(symname, Getattr(e, "sym:name")) == 0)) { +	      Swig_warning(WARN_LANG_DEREF_SHADOW, Getfile(e), Getline(e), "Declaration of '%s' shadows declaration accessible via operator->(),\n", name); +	      Swig_warning(WARN_LANG_DEREF_SHADOW, Getfile(c), Getline(c), "previous declaration of '%s'.\n", name); +	    } else { +	      /* Make sure node with same name doesn't already exist */ +	      int k; +	      int match = 0; +	      for (k = 0; k < Len(methods); k++) { +		e = Getitem(methods, k); +		if (Cmp(symname, Getattr(e, "sym:name")) == 0) { +		  match = 1; +		  break; +		} +		if (!Getattr(e, "sym:name") && (Cmp(name, Getattr(e, "name")) == 0)) { +		  match = 1; +		  break; +		} +	      } +	      if (!match) { +		Node *cc = c; +		while (cc) { +		  Node *cp = cc; +		  if (classname) { +		    Setattr(cp, "extendsmartclassname", classname); +		  } +		  Setattr(cp, "allocate:smartpointeraccess", "1"); +		  /* If constant, we have to be careful */ +		  if (isconst) { +		    SwigType *decl = Getattr(cp, "decl"); +		    if (decl) { +		      if (SwigType_isfunction(decl)) {	/* If method, we only add if it's a const method */ +			if (SwigType_isconst(decl)) { +			  Append(methods, cp); +			} +		      } else { +			Append(methods, cp); +		      } +		    } else { +		      Append(methods, cp); +		    } +		  } else { +		    Append(methods, cp); +		  } +		  cc = Getattr(cc, "sym:nextSibling"); +		} +	      } +	    } +	  } +	} +      } + +      c = nextSibling(c); +    } +    /* Look for methods in base classes */ +    { +      Node *bases = Getattr(cls, "bases"); +      int k; +      for (k = 0; k < Len(bases); k++) { +	smart_pointer_methods(Getitem(bases, k), methods, isconst); +      } +    } +    /* Remove protected/private members */ +    { +      for (int i = 0; i < Len(methods);) { +	Node *n = Getitem(methods, i); +	if (!is_public(n)) { +	  Delitem(methods, i); +	  continue; +	} +	i++; +      } +    } +    return methods; +  } + +  void mark_exception_classes(ParmList *p) { +    while (p) { +      SwigType *ty = Getattr(p, "type"); +      SwigType *t = SwigType_typedef_resolve_all(ty); +      if (SwigType_isreference(t) || SwigType_ispointer(t) || SwigType_isarray(t)) { +	Delete(SwigType_pop(t)); +      } +      Node *c = Swig_symbol_clookup(t, 0); +      if (c) { +	if (!GetFlag(c, "feature:exceptionclass")) { +	  SetFlag(c, "feature:exceptionclass"); +	} +      } +      p = nextSibling(p); +      Delete(t); +    } +  } + + +  void process_exceptions(Node *n) { +    ParmList *catchlist = 0; +    /*  +       the "catchlist" attribute is used to emit the block + +       try {$action;}  +       catch <list of catches>; + +       in emit.cxx + +       and is either constructed from the "feature:catches" feature +       or copied from the node "throws" list. +     */ +    String *scatchlist = Getattr(n, "feature:catches"); +    if (scatchlist) { +      catchlist = Swig_cparse_parms(scatchlist, n); +      if (catchlist) { +	Setattr(n, "catchlist", catchlist); +	mark_exception_classes(catchlist); +	Delete(catchlist); +      } +    } +    ParmList *throws = Getattr(n, "throws"); +    if (throws) { +      /* if there is no explicit catchlist, we catch everything in the throws list */ +      if (!catchlist) { +	Setattr(n, "catchlist", throws); +      } +      mark_exception_classes(throws); +    } +  } + +public: +Allocate(): +  inclass(NULL), extendmode(0) { +  } + +  virtual int top(Node *n) { +    cplus_mode = PUBLIC; +    inclass = 0; +    extendmode = 0; +    emit_children(n); +    return SWIG_OK; +  } + +  virtual int importDirective(Node *n) { +    return emit_children(n); +  } +  virtual int includeDirective(Node *n) { +    return emit_children(n); +  } +  virtual int externDeclaration(Node *n) { +    return emit_children(n); +  } +  virtual int namespaceDeclaration(Node *n) { +    return emit_children(n); +  } +  virtual int extendDirective(Node *n) { +    extendmode = 1; +    emit_children(n); +    extendmode = 0; +    return SWIG_OK; +  } + +  virtual int classDeclaration(Node *n) { +    Symtab *symtab = Swig_symbol_current(); +    Swig_symbol_setscope(Getattr(n, "symtab")); +    save_value<Node*> oldInclass(inclass); +    save_value<AccessMode> oldAcessMode(cplus_mode); +    save_value<int> oldExtendMode(extendmode); +    if (Getattr(n, "template")) +      extendmode = 0; +    if (!CPlusPlus) { +      /* Always have default constructors/destructors in C */ +      Setattr(n, "allocate:default_constructor", "1"); +      Setattr(n, "allocate:default_destructor", "1"); +    } + +    if (Getattr(n, "allocate:visit")) +      return SWIG_OK; +    Setattr(n, "allocate:visit", "1"); + +    /* Always visit base classes first */ +    { +      List *bases = Getattr(n, "bases"); +      if (bases) { +	for (int i = 0; i < Len(bases); i++) { +	  Node *b = Getitem(bases, i); +	  classDeclaration(b); +	} +      } +    } +    inclass = n; +    String *kind = Getattr(n, "kind"); +    if (Strcmp(kind, "class") == 0) { +      cplus_mode = PRIVATE; +    } else { +      cplus_mode = PUBLIC; +    } + +    emit_children(n); + +    /* Check if the class is abstract via inheritance.   This might occur if a class didn't have +       any pure virtual methods of its own, but it didn't implement all of the pure methods in +       a base class */ +    if (!Getattr(n, "abstracts") && is_abstract_inherit(n)) { +      if (((Getattr(n, "allocate:public_constructor") || (!GetFlag(n, "feature:nodefault") && !Getattr(n, "allocate:has_constructor"))))) { +	if (!GetFlag(n, "feature:notabstract")) { +	  Node *na = Getattr(n, "abstracts:firstnode"); +	  if (na) { +	    Swig_warning(WARN_TYPE_ABSTRACT, Getfile(n), Getline(n), +			 "Class '%s' might be abstract, " "no constructors generated,\n", SwigType_namestr(Getattr(n, "name"))); +	    Swig_warning(WARN_TYPE_ABSTRACT, Getfile(na), Getline(na), "Method %s might not be implemented.\n", Swig_name_decl(na)); +	    if (!Getattr(n, "abstracts")) { +	      List *abstracts = NewList(); +	      Append(abstracts, na); +	      Setattr(n, "abstracts", abstracts); +	      Delete(abstracts); +	    } +	  } +	} +      } +    } + +    if (!Getattr(n, "allocate:has_constructor")) { +      /* No constructor is defined.  We need to check a few things */ +      /* If class is abstract.  No default constructor. Sorry */ +      if (Getattr(n, "abstracts")) { +	Delattr(n, "allocate:default_constructor"); +      } +      if (!Getattr(n, "allocate:default_constructor")) { +	/* Check base classes */ +	List *bases = Getattr(n, "allbases"); +	int allows_default = 1; + +	for (int i = 0; i < Len(bases); i++) { +	  Node *n = Getitem(bases, i); +	  /* If base class does not allow default constructor, we don't allow it either */ +	  if (!Getattr(n, "allocate:default_constructor") && (!Getattr(n, "allocate:default_base_constructor"))) { +	    allows_default = 0; +	  } +	} +	if (allows_default) { +	  Setattr(n, "allocate:default_constructor", "1"); +	} +      } +    } +    if (!Getattr(n, "allocate:has_copy_constructor")) { +      if (Getattr(n, "abstracts")) { +	Delattr(n, "allocate:copy_constructor"); +      } +      if (!Getattr(n, "allocate:copy_constructor")) { +	/* Check base classes */ +	List *bases = Getattr(n, "allbases"); +	int allows_copy = 1; + +	for (int i = 0; i < Len(bases); i++) { +	  Node *n = Getitem(bases, i); +	  /* If base class does not allow copy constructor, we don't allow it either */ +	  if (!Getattr(n, "allocate:copy_constructor") && (!Getattr(n, "allocate:copy_base_constructor"))) { +	    allows_copy = 0; +	  } +	} +	if (allows_copy) { +	  Setattr(n, "allocate:copy_constructor", "1"); +	} +      } +    } + +    if (!Getattr(n, "allocate:has_destructor")) { +      /* No destructor was defined */ +      List *bases = Getattr(n, "allbases"); +      int allows_destruct = 1; + +      for (int i = 0; i < Len(bases); i++) { +	Node *n = Getitem(bases, i); +	/* If base class does not allow default destructor, we don't allow it either */ +	if (!Getattr(n, "allocate:default_destructor") && (!Getattr(n, "allocate:default_base_destructor"))) { +	  allows_destruct = 0; +	} +      } +      if (allows_destruct) { +	Setattr(n, "allocate:default_destructor", "1"); +      } +    } + +    if (!Getattr(n, "allocate:has_assign")) { +      /* No assignment operator was defined */ +      List *bases = Getattr(n, "allbases"); +      int allows_assign = 1; + +      for (int i = 0; i < Len(bases); i++) { +	Node *n = Getitem(bases, i); +	/* If base class does not allow assignment, we don't allow it either */ +	if (Getattr(n, "allocate:has_assign")) { +	  allows_assign = !Getattr(n, "allocate:noassign"); +	} +      } +      if (!allows_assign) { +	Setattr(n, "allocate:noassign", "1"); +      } +    } + +    if (!Getattr(n, "allocate:has_new")) { +      /* No new operator was defined */ +      List *bases = Getattr(n, "allbases"); +      int allows_new = 1; + +      for (int i = 0; i < Len(bases); i++) { +	Node *n = Getitem(bases, i); +	/* If base class does not allow new operator, we don't allow it either */ +	if (Getattr(n, "allocate:has_new")) { +	  allows_new = !Getattr(n, "allocate:nonew"); +	} +      } +      if (!allows_new) { +	Setattr(n, "allocate:nonew", "1"); +      } +    } + +    /* Check if base classes allow smart pointers, but might be hidden */ +    if (!Getattr(n, "allocate:smartpointer")) { +      Node *sp = Swig_symbol_clookup("operator ->", 0); +      if (sp) { +	/* Look for parent */ +	Node *p = parentNode(sp); +	if (Strcmp(nodeType(p), "extend") == 0) { +	  p = parentNode(p); +	} +	if (Strcmp(nodeType(p), "class") == 0) { +	  if (GetFlag(p, "feature:ignore")) { +	    Setattr(n, "allocate:smartpointer", Getattr(p, "allocate:smartpointer")); +	  } +	} +      } +    } + +    Swig_interface_propagate_methods(n); + +    /* Only care about default behavior.  Remove temporary values */ +    Setattr(n, "allocate:visit", "1"); +    Swig_symbol_setscope(symtab); +    return SWIG_OK; +  } + +  virtual int accessDeclaration(Node *n) { +    String *kind = Getattr(n, "kind"); +    if (Cmp(kind, "public") == 0) { +      cplus_mode = PUBLIC; +    } else if (Cmp(kind, "private") == 0) { +      cplus_mode = PRIVATE; +    } else if (Cmp(kind, "protected") == 0) { +      cplus_mode = PROTECTED; +    } +    return SWIG_OK; +  } + +  virtual int usingDeclaration(Node *n) { + +    Node *c = 0; +    for (c = firstChild(n); c; c = nextSibling(c)) { +      if (Strcmp(nodeType(c), "cdecl") == 0) { +	process_exceptions(c); + +	if (inclass) +	  class_member_is_defined_in_bases(c, inclass); +      } +    } + +    return SWIG_OK; +  } + +  virtual int cDeclaration(Node *n) { + +    process_exceptions(n); + +    if (inclass) { +      /* check whether the member node n is defined in class node in class's bases */ +      class_member_is_defined_in_bases(n, inclass); + +      /* Check to see if this is a static member or not.  If so, we add an attribute +         cplus:staticbase that saves the current class */ + +      if (Swig_storage_isstatic(n)) { +	Setattr(n, "cplus:staticbase", inclass); +      } else if (Cmp(Getattr(n, "kind"), "variable") == 0) { +        /* Check member variable to determine whether assignment is valid */ +        if (SwigType_isreference(Getattr(n, "type"))) { +          /* Can't assign a class with reference member data */ +	  Setattr(inclass, "allocate:noassign", "1"); +        } +      } + +      String *name = Getattr(n, "name"); +      if (cplus_mode != PUBLIC) { +	if (Strcmp(name, "operator =") == 0) { +	  /* Look for a private assignment operator */ +	  if (!GetFlag(n, "deleted")) +	    Setattr(inclass, "allocate:has_assign", "1"); +	  Setattr(inclass, "allocate:noassign", "1"); +	} else if (Strcmp(name, "operator new") == 0) { +	  /* Look for a private new operator */ +	  if (!GetFlag(n, "deleted")) +	    Setattr(inclass, "allocate:has_new", "1"); +	  Setattr(inclass, "allocate:nonew", "1"); +	} +      } else { +	if (Strcmp(name, "operator =") == 0) { +	  if (!GetFlag(n, "deleted")) +	    Setattr(inclass, "allocate:has_assign", "1"); +	  else +	    Setattr(inclass, "allocate:noassign", "1"); +	} else if (Strcmp(name, "operator new") == 0) { +	  if (!GetFlag(n, "deleted")) +	    Setattr(inclass, "allocate:has_new", "1"); +	  else +	    Setattr(inclass, "allocate:nonew", "1"); +	} +	/* Look for smart pointer operator */ +	if ((Strcmp(name, "operator ->") == 0) && (!GetFlag(n, "feature:ignore"))) { +	  /* Look for version with no parameters */ +	  Node *sn = n; +	  while (sn) { +	    if (!Getattr(sn, "parms")) { +	      SwigType *type = SwigType_typedef_resolve_all(Getattr(sn, "type")); +	      SwigType_push(type, Getattr(sn, "decl")); +	      Delete(SwigType_pop_function(type)); +	      SwigType *base = SwigType_base(type); +	      Node *sc = Swig_symbol_clookup(base, 0); +	      if ((sc) && (Strcmp(nodeType(sc), "class") == 0)) { +		if (SwigType_check_decl(type, "p.")) { +		  /* Need to check if type is a const pointer */ +		  int isconst = 0; +		  Delete(SwigType_pop(type)); +		  if (SwigType_isconst(type)) { +		    isconst = !Getattr(inclass, "allocate:smartpointermutable"); +		    Setattr(inclass, "allocate:smartpointerconst", "1"); +		  } +		  else { +		    Setattr(inclass, "allocate:smartpointermutable", "1"); +		  } +		  List *methods = smart_pointer_methods(sc, 0, isconst); +		  Setattr(inclass, "allocate:smartpointer", methods); +		  Setattr(inclass, "allocate:smartpointerpointeeclassname", Getattr(sc, "name")); +		} else { +		  /* Hmmm.  The return value is not a pointer.  If the type is a value +		     or reference.  We're going to chase it to see if another operator->() +		     can be found */ +		  if ((SwigType_check_decl(type, "")) || (SwigType_check_decl(type, "r."))) { +		    Node *nn = Swig_symbol_clookup("operator ->", Getattr(sc, "symtab")); +		    if (nn) { +		      Delete(base); +		      Delete(type); +		      sn = nn; +		      continue; +		    } +		  } +		} +	      } +	      Delete(base); +	      Delete(type); +	      break; +	    } +	  } +	} +      } +    } +    return SWIG_OK; +  } + +  virtual int constructorDeclaration(Node *n) { +    if (!inclass) +      return SWIG_OK; +    Parm *parms = Getattr(n, "parms"); + +    process_exceptions(n); +    if (!extendmode) { +      if (!ParmList_numrequired(parms)) { +	/* Class does define a default constructor */ +	/* However, we had better see where it is defined */ +	if (cplus_mode == PUBLIC) { +	  Setattr(inclass, "allocate:default_constructor", "1"); +	} else if (cplus_mode == PROTECTED) { +	  Setattr(inclass, "allocate:default_base_constructor", "1"); +	} +      } +      /* Class defines some kind of constructor. May or may not be public */ +      Setattr(inclass, "allocate:has_constructor", "1"); +      if (cplus_mode == PUBLIC) { +	Setattr(inclass, "allocate:public_constructor", "1"); +      } +    } else { +      Setattr(inclass, "allocate:has_constructor", "1"); +      Setattr(inclass, "allocate:public_constructor", "1"); +    } + + +    /* See if this is a copy constructor */ +    if (parms && (ParmList_numrequired(parms) == 1)) { +      /* Look for a few cases. X(const X &), X(X &), X(X *) */ +      int copy_constructor = 0; +      SwigType *type = Getattr(inclass, "name"); +      String *tn = NewStringf("r.q(const).%s", type); +      String *cc = SwigType_typedef_resolve_all(tn); +      SwigType *rt = SwigType_typedef_resolve_all(Getattr(parms, "type")); +      if (SwigType_istemplate(type)) { +	String *tmp = Swig_symbol_template_deftype(cc, 0); +	Delete(cc); +	cc = tmp; +	tmp = Swig_symbol_template_deftype(rt, 0); +	Delete(rt); +	rt = tmp; +      } +      if (Strcmp(cc, rt) == 0) { +	copy_constructor = 1; +      } else { +	Delete(cc); +	cc = NewStringf("r.%s", Getattr(inclass, "name")); +	if (Strcmp(cc, Getattr(parms, "type")) == 0) { +	  copy_constructor = 1; +	} else { +	  Delete(cc); +	  cc = NewStringf("p.%s", Getattr(inclass, "name")); +	  String *ty = SwigType_strip_qualifiers(Getattr(parms, "type")); +	  if (Strcmp(cc, ty) == 0) { +	    copy_constructor = 1; +	  } +	  Delete(ty); +	} +      } +      Delete(cc); +      Delete(rt); +      Delete(tn); + +      if (copy_constructor) { +	Setattr(n, "copy_constructor", "1"); +	Setattr(inclass, "allocate:has_copy_constructor", "1"); +	if (cplus_mode == PUBLIC) { +	  Setattr(inclass, "allocate:copy_constructor", "1"); +	} else if (cplus_mode == PROTECTED) { +	  Setattr(inclass, "allocate:copy_base_constructor", "1"); +	} +      } +    } +    return SWIG_OK; +  } + +  virtual int destructorDeclaration(Node *n) { +    (void) n; +    if (!inclass) +      return SWIG_OK; +    if (!extendmode) { +      Setattr(inclass, "allocate:has_destructor", "1"); +      if (cplus_mode == PUBLIC) { +	Setattr(inclass, "allocate:default_destructor", "1"); +      } else if (cplus_mode == PROTECTED) { +	Setattr(inclass, "allocate:default_base_destructor", "1"); +      } else if (cplus_mode == PRIVATE) { +	Setattr(inclass, "allocate:private_destructor", "1"); +      } +    } else { +      Setattr(inclass, "allocate:has_destructor", "1"); +      Setattr(inclass, "allocate:default_destructor", "1"); +    } +    return SWIG_OK; +  } +}; + +void Swig_default_allocators(Node *n) { +  if (!n) +    return; +  Allocate *a = new Allocate; +  a->top(n); +  delete a; +} diff --git a/contrib/tools/swig/Source/Modules/contract.cxx b/contrib/tools/swig/Source/Modules/contract.cxx new file mode 100644 index 00000000000..dfc85ebe761 --- /dev/null +++ b/contrib/tools/swig/Source/Modules/contract.cxx @@ -0,0 +1,358 @@ +/* -----------------------------------------------------------------------------  + * This file is part of SWIG, which is licensed as a whole under version 3  + * (or any later version) of the GNU General Public License. Some additional + * terms also apply to certain portions of SWIG. The full details of the SWIG + * license and copyrights can be found in the LICENSE and COPYRIGHT files + * included with the SWIG source code as distributed by the SWIG developers + * and at https://www.swig.org/legal.html. + * + * contract.cxx + * + * Support for Wrap by Contract in SWIG. + * ----------------------------------------------------------------------------- */ + +#include "swigmod.h" + +/* Contract structure.  This holds rules about the different kinds of contract sections +   and their combination rules */ + +struct contract { +  const char *section; +  const char *combiner; +}; +/* Contract rules.  This table defines what contract sections are recognized as well as +   how contracts are to combined via inheritance */ + +static contract Rules[] = { +  {"require:", "&&"}, +  {"ensure:", "||"}, +  {NULL, NULL} +}; + +/* ---------------------------------------------------------------------------- + * class Contracts: + * + * This class defines the functions that need to be used in  + *         "wrap by contract" module. + * ------------------------------------------------------------------------- */ + +class Contracts:public Dispatcher { +  String *make_expression(String *s, Node *n); +  void substitute_parms(String *s, ParmList *p, int method); +public: +  Hash *ContractSplit(Node *n); +  int emit_contract(Node *n, int method); +  int cDeclaration(Node *n); +  int constructorDeclaration(Node *n); +  int externDeclaration(Node *n); +  int extendDirective(Node *n); +  int importDirective(Node *n); +  int includeDirective(Node *n); +  int namespaceDeclaration(Node *n); +  int classDeclaration(Node *n); +  virtual int top(Node *n); +}; + +static int Contract_Mode = 0;	/* contract option */ +static int InClass = 0;		/* Parsing C++ or not */ +static int InConstructor = 0; +static Node *CurrentClass = 0; + +/* Set the contract mode, default is 0 (not open) */ +/* Normally set in main.cxx, when get the "-contracts" option */ +void Swig_contract_mode_set(int flag) { +  Contract_Mode = flag; +} + +/* Get the contract mode */ +int Swig_contract_mode_get() { +  return Contract_Mode; +} + +/* Apply contracts */ +void Swig_contracts(Node *n) { + +  Contracts *a = new Contracts; +  a->top(n); +  delete a; +} + +/* Split the whole contract into preassertion, postassertion and others */ +Hash *Contracts::ContractSplit(Node *n) { + +  String *contract = Getattr(n, "feature:contract"); +  Hash *result; +  if (!contract) +    return NULL; + +  result = NewHash(); +  String *current_section = NewString(""); +  const char *current_section_name = Rules[0].section; +  List *l = SplitLines(contract); + +  Iterator i; +  for (i = First(l); i.item; i = Next(i)) { +    int found = 0; +    if (Strchr(i.item, '{')) +      continue; +    if (Strchr(i.item, '}')) +      continue; +    for (int j = 0; Rules[j].section; j++) { +      if (Strstr(i.item, Rules[j].section)) { +	if (Len(current_section)) { +	  Setattr(result, current_section_name, current_section); +	  current_section = Getattr(result, Rules[j].section); +	  if (!current_section) +	    current_section = NewString(""); +	} +	current_section_name = Rules[j].section; +	found = 1; +	break; +      } +    } +    if (!found) +      Append(current_section, i.item); +  } +  if (Len(current_section)) +    Setattr(result, current_section_name, current_section); +  return result; +} + +/* This function looks in base classes and collects contracts found */ +void inherit_contracts(Node *c, Node *n, Hash *contracts, Hash *messages) { + +  Node *b, *temp; +  String *name, *type, *local_decl, *base_decl; +  List *bases; +  int found = 0; + +  bases = Getattr(c, "bases"); +  if (!bases) +    return; + +  name = Getattr(n, "name"); +  type = Getattr(n, "type"); +  local_decl = Getattr(n, "decl"); +  if (local_decl) { +    local_decl = SwigType_typedef_resolve_all(local_decl); +  } else { +    return; +  } +  /* Width first search */ +  for (int i = 0; i < Len(bases); i++) { +    b = Getitem(bases, i); +    temp = firstChild(b); +    while (temp) { +      base_decl = Getattr(temp, "decl"); +      if (base_decl) { +	base_decl = SwigType_typedef_resolve_all(base_decl); +	if ((checkAttribute(temp, "storage", "virtual")) && +	    (checkAttribute(temp, "name", name)) && (checkAttribute(temp, "type", type)) && (!Strcmp(local_decl, base_decl))) { +	  /* Yes, match found. */ +	  Hash *icontracts = Getattr(temp, "contract:rules"); +	  Hash *imessages = Getattr(temp, "contract:messages"); +	  found = 1; +	  if (icontracts && imessages) { +	    /* Add inherited contracts and messages to the contract rules above */ +	    int j = 0; +	    for (j = 0; Rules[j].section; j++) { +	      String *t = Getattr(contracts, Rules[j].section); +	      String *s = Getattr(icontracts, Rules[j].section); +	      if (s) { +		if (t) { +		  Insert(t, 0, "("); +		  Printf(t, ") %s (%s)", Rules[j].combiner, s); +		  String *m = Getattr(messages, Rules[j].section); +		  Printf(m, " %s [%s from %s]", Rules[j].combiner, Getattr(imessages, Rules[j].section), Getattr(b, "name")); +		} else { +		  Setattr(contracts, Rules[j].section, NewString(s)); +		  Setattr(messages, Rules[j].section, NewStringf("[%s from %s]", Getattr(imessages, Rules[j].section), Getattr(b, "name"))); +		} +	      } +	    } +	  } +	} +	Delete(base_decl); +      } +      temp = nextSibling(temp); +    } +  } +  Delete(local_decl); +  if (!found) { +    for (int j = 0; j < Len(bases); j++) { +      b = Getitem(bases, j); +      inherit_contracts(b, n, contracts, messages); +    } +  } +} + +/* This function cleans up the assertion string by removing some extraneous characters. +   Splitting the assertion into pieces */ + +String *Contracts::make_expression(String *s, Node *n) { +  String *str_assert, *expr = 0; +  List *list_assert; + +  str_assert = NewString(s); +  /* Omit all useless characters and split by ; */ +  Replaceall(str_assert, "\n", ""); +  Replaceall(str_assert, "{", ""); +  Replaceall(str_assert, "}", ""); +  Replace(str_assert, " ", "", DOH_REPLACE_ANY | DOH_REPLACE_NOQUOTE); +  Replace(str_assert, "\t", "", DOH_REPLACE_ANY | DOH_REPLACE_NOQUOTE); + +  list_assert = Split(str_assert, ';', -1); +  Delete(str_assert); + +  /* build up new assertion */ +  str_assert = NewString(""); +  Iterator ei; + +  for (ei = First(list_assert); ei.item; ei = Next(ei)) { +    expr = ei.item; +    if (Len(expr)) { +      Replaceid(expr, Getattr(n, "name"), Swig_cresult_name()); +      if (Len(str_assert)) +	Append(str_assert, "&&"); +      Printf(str_assert, "(%s)", expr); +    } +  } +  Delete(list_assert); +  return str_assert; +} + +/* This function substitutes parameter names for argument names in the +   contract specification.  Note: it is assumed that the wrapper code  +   uses arg1 for self and arg2..argn for arguments. */ + +void Contracts::substitute_parms(String *s, ParmList *p, int method) { +  int argnum = 1; +  char argname[32]; + +  if (method) { +    Replaceid(s, "$self", "arg1"); +    argnum++; +  } +  while (p) { +    sprintf(argname, "arg%d", argnum); +    String *name = Getattr(p, "name"); +    if (name) { +      Replaceid(s, name, argname); +    } +    argnum++; +    p = nextSibling(p); +  } +} + +int Contracts::emit_contract(Node *n, int method) { +  Hash *contracts; +  Hash *messages; +  String *c; + +  ParmList *cparms; + +  if (!Getattr(n, "feature:contract")) +    return SWIG_ERROR; + +  /* Get contract parameters */ +  cparms = Getmeta(Getattr(n, "feature:contract"), "parms"); + +  /*  Split contract into preassert & postassert */ +  contracts = ContractSplit(n); +  if (!contracts) +    return SWIG_ERROR; + +  /* This messages hash is used to hold the error messages that will be displayed on +     failed contract. */ + +  messages = NewHash(); + +  /* Take the different contract expressions and clean them up a bit */ +  Iterator i; +  for (i = First(contracts); i.item; i = Next(i)) { +    String *e = make_expression(i.item, n); +    substitute_parms(e, cparms, method); +    Setattr(contracts, i.key, e); + +    /* Make a string containing error messages */ +    Setattr(messages, i.key, NewString(e)); +  } + +  /* If we're in a class. We need to inherit other assertions. */ +  if (InClass) { +    inherit_contracts(CurrentClass, n, contracts, messages); +  } + +  /* Save information */ +  Setattr(n, "contract:rules", contracts); +  Setattr(n, "contract:messages", messages); + +  /* Okay.  Generate the contract runtime code. */ + +  if ((c = Getattr(contracts, "require:"))) { +    Setattr(n, "contract:preassert", NewStringf("SWIG_contract_assert(%s, \"Contract violation: require: %s\");\n", c, Getattr(messages, "require:"))); +  } +  if ((c = Getattr(contracts, "ensure:"))) { +    Setattr(n, "contract:postassert", NewStringf("SWIG_contract_assert(%s, \"Contract violation: ensure: %s\");\n", c, Getattr(messages, "ensure:"))); +  } +  return SWIG_OK; +} + +int Contracts::cDeclaration(Node *n) { +  int ret = SWIG_OK; +  String *decl = Getattr(n, "decl"); + +  /* Not a function.  Don't even bother with it (for now) */ +  if (!SwigType_isfunction(decl)) +    return SWIG_OK; + +  if (Getattr(n, "feature:contract")) +    ret = emit_contract(n, InClass && !Swig_storage_isstatic(n)); +  return ret; +} + +int Contracts::constructorDeclaration(Node *n) { +  int ret = SWIG_OK; +  InConstructor = 1; +  if (Getattr(n, "feature:contract")) +    ret = emit_contract(n, 0); +  InConstructor = 0; +  return ret; +} + +int Contracts::externDeclaration(Node *n) { +  return emit_children(n); +} + +int Contracts::extendDirective(Node *n) { +  return emit_children(n); +} + +int Contracts::importDirective(Node *n) { +  return emit_children(n); +} + +int Contracts::includeDirective(Node *n) { +  return emit_children(n); +} + +int Contracts::namespaceDeclaration(Node *n) { +  return emit_children(n); +} + +int Contracts::classDeclaration(Node *n) { +  int ret = SWIG_OK; +  int oldInClass = InClass; +  Node *oldClass = CurrentClass; +  InClass = 1; +  CurrentClass = n; +  emit_children(n); +  InClass = oldInClass; +  CurrentClass = oldClass; +  return ret; +} + +int Contracts::top(Node *n) { +  emit_children(n); +  return SWIG_OK; +} diff --git a/contrib/tools/swig/Source/Modules/csharp.cxx b/contrib/tools/swig/Source/Modules/csharp.cxx new file mode 100644 index 00000000000..240a002b40e --- /dev/null +++ b/contrib/tools/swig/Source/Modules/csharp.cxx @@ -0,0 +1,4616 @@ +/* ----------------------------------------------------------------------------- + * This file is part of SWIG, which is licensed as a whole under version 3  + * (or any later version) of the GNU General Public License. Some additional + * terms also apply to certain portions of SWIG. The full details of the SWIG + * license and copyrights can be found in the LICENSE and COPYRIGHT files + * included with the SWIG source code as distributed by the SWIG developers + * and at https://www.swig.org/legal.html. + * + * csharp.cxx + * + * C# language module for SWIG. + * ----------------------------------------------------------------------------- */ + +#include "swigmod.h" +#include "cparse.h" +#include <limits.h>		// for INT_MAX +#include <ctype.h> + +/* Hash type used for upcalls from C/C++ */ +typedef DOH UpcallData; + +class CSHARP:public Language { +  static const char *usage; +  const String *empty_string; +  const String *public_string; +  const String *protected_string; + +  Hash *swig_types_hash; +  File *f_begin; +  File *f_runtime; +  File *f_runtime_h; +  File *f_header; +  File *f_wrappers; +  File *f_init; +  File *f_directors; +  File *f_directors_h; +  File *f_single_out; +  List *filenames_list; + +  bool proxy_flag;		// Flag for generating proxy classes +  bool native_function_flag;	// Flag for when wrapping a native function +  bool enum_constant_flag;	// Flag for when wrapping an enum or constant +  bool static_flag;		// Flag for when wrapping a static functions or member variables +  bool variable_wrapper_flag;	// Flag for when wrapping a nonstatic member variable +  bool wrapping_member_flag;	// Flag for when wrapping a member variable/enum/const +  bool global_variable_flag;	// Flag for when wrapping a global variable +  bool old_variable_names;	// Flag for old style variable names in the intermediary class +  bool generate_property_declaration_flag;	// Flag for generating properties + +  String *imclass_name;		// intermediary class name +  String *module_class_name;	// module class name +  String *imclass_class_code;	// intermediary class code +  String *proxy_class_def; +  String *proxy_class_code; +  String *interface_class_code; // if %feature("interface") was declared for a class, here goes the interface declaration +  String *module_class_code; +  String *proxy_class_name;	// proxy class name +  String *full_imclass_name;	// fully qualified intermediary class name when using nspace feature, otherwise same as imclass_name +  String *variable_name;	//Name of a variable being wrapped +  String *proxy_class_constants_code; +  String *module_class_constants_code; +  String *enum_code; +  String *dllimport;		// DllImport attribute name +  String *namespce;		// Optional namespace name +  String *imclass_imports;	//intermediary class imports from %pragma +  String *module_imports;	//module imports from %pragma +  String *imclass_baseclass;	//inheritance for intermediary class class from %pragma +  String *module_baseclass;	//inheritance for module class from %pragma +  String *imclass_interfaces;	//interfaces for intermediary class class from %pragma +  String *module_interfaces;	//interfaces for module class from %pragma +  String *imclass_class_modifiers;	//class modifiers for intermediary class overridden by %pragma +  String *module_class_modifiers;	//class modifiers for module class overridden by %pragma +  String *upcasts_code;		//C++ casts for inheritance hierarchies C++ code +  String *imclass_cppcasts_code;	//C++ casts up inheritance hierarchies intermediary class code +  String *director_callback_typedefs;	// Director function pointer typedefs for callbacks +  String *director_callbacks;	// Director callback function pointer member variables +  String *director_delegate_callback;	// Director callback method that delegates are set to call +  String *director_delegate_definitions;	// Director delegates definitions in proxy class +  String *director_delegate_instances;	// Director delegates member variables in proxy class +  String *director_method_types;	// Director method types +  String *director_connect_parms;	// Director delegates parameter list for director connect call +  String *destructor_call;	//C++ destructor call if any +  String *output_file;		// File name for single file mode. If set all generated code will be written to this file + +  // Director method stuff: +  List *dmethods_seq; +  Hash *dmethods_table; +  int n_dmethods; +  int n_directors; +  int first_class_dmethod; +  int curr_class_dmethod; +  int nesting_depth; + +  enum EnumFeature { SimpleEnum, TypeunsafeEnum, TypesafeEnum, ProperEnum }; + +public: + +  /* ----------------------------------------------------------------------------- +   * CSHARP() +   * ----------------------------------------------------------------------------- */ + +   CSHARP():empty_string(NewString("")), +      public_string(NewString("public")), +      protected_string(NewString("protected")), +      swig_types_hash(NULL), +      f_begin(NULL), +      f_runtime(NULL), +      f_runtime_h(NULL), +      f_header(NULL), +      f_wrappers(NULL), +      f_init(NULL), +      f_directors(NULL), +      f_directors_h(NULL), +      f_single_out(NULL), +      filenames_list(NULL), +      proxy_flag(true), +      native_function_flag(false), +      enum_constant_flag(false), +      static_flag(false), +      variable_wrapper_flag(false), +      wrapping_member_flag(false), +      global_variable_flag(false), +      old_variable_names(false), +      generate_property_declaration_flag(false), +      imclass_name(NULL), +      module_class_name(NULL), +      imclass_class_code(NULL), +      proxy_class_def(NULL), +      proxy_class_code(NULL), +      interface_class_code(NULL), +      module_class_code(NULL), +      proxy_class_name(NULL), +      full_imclass_name(NULL), +      variable_name(NULL), +      proxy_class_constants_code(NULL), +      module_class_constants_code(NULL), +      enum_code(NULL), +      dllimport(NULL), +      namespce(NULL), +      imclass_imports(NULL), +      module_imports(NULL), +      imclass_baseclass(NULL), +      module_baseclass(NULL), +      imclass_interfaces(NULL), +      module_interfaces(NULL), +      imclass_class_modifiers(NULL), +      module_class_modifiers(NULL), +      upcasts_code(NULL), +      imclass_cppcasts_code(NULL), +      director_callback_typedefs(NULL), +      director_callbacks(NULL), +      director_delegate_callback(NULL), +      director_delegate_definitions(NULL), +      director_delegate_instances(NULL), +      director_method_types(NULL), +      director_connect_parms(NULL), +      destructor_call(NULL), +      output_file(NULL), +      dmethods_seq(NULL), +      dmethods_table(NULL), +      n_dmethods(0), +      n_directors(0), +      first_class_dmethod(0), +      curr_class_dmethod(0), +      nesting_depth(0){ +    /* for now, multiple inheritance in directors is disabled, this +       should be easy to implement though */ +    director_multiple_inheritance = 0; +    director_language = 1; +  } + +  /* ----------------------------------------------------------------------------- +   * getProxyName() +   * +   * Test to see if a type corresponds to something wrapped with a proxy class. +   * Return NULL if not otherwise the proxy class name, fully qualified with +   * a namespace if the nspace feature is used. +   * ----------------------------------------------------------------------------- */ +   +   String *getProxyName(SwigType *t) { +     String *proxyname = NULL; +     if (proxy_flag) { +       Node *n = classLookup(t); +       if (n) { +	 proxyname = Getattr(n, "proxyname"); +	 if (!proxyname) { +	   String *nspace = Getattr(n, "sym:nspace"); +	   String *symname = Copy(Getattr(n, "sym:name")); +	   if (symname && !GetFlag(n, "feature:flatnested")) { +	     for (Node *outer_class = Getattr(n, "nested:outer"); outer_class; outer_class = Getattr(outer_class, "nested:outer")) { +               if (String* name = Getattr(outer_class, "sym:name")) { +                 Push(symname, "."); +                 Push(symname, name); +               } +               else +                 return NULL; +	     } +	   } +	   if (nspace) { +	     if (namespce) +	       proxyname = NewStringf("%s.%s.%s", namespce, nspace, symname); +	     else +	       proxyname = NewStringf("%s.%s", nspace, symname); +	   } else { +	     proxyname = Copy(symname); +	   } +	   Setattr(n, "proxyname", proxyname); +	   Delete(proxyname); +	   Delete(symname); +	 } +       } +     } +     return proxyname; +   } + +  /* ------------------------------------------------------------ +   * main() +   * ------------------------------------------------------------ */ + +  virtual void main(int argc, char *argv[]) { + +    SWIG_library_directory("csharp"); + +    // Look for certain command line options +    for (int i = 1; i < argc; i++) { +      if (argv[i]) { +	if (strcmp(argv[i], "-dllimport") == 0) { +	  if (argv[i + 1]) { +	    dllimport = NewString(""); +	    Printf(dllimport, argv[i + 1]); +	    Swig_mark_arg(i); +	    Swig_mark_arg(i + 1); +	    i++; +	  } else { +	    Swig_arg_error(); +	  } +	} else if (strcmp(argv[i], "-namespace") == 0) { +	  if (argv[i + 1]) { +	    namespce = NewString(""); +	    Printf(namespce, argv[i + 1]); +	    if (Len(namespce) == 0) { +	      Delete(namespce); +	      namespce = 0; +	    } +	    Swig_mark_arg(i); +	    Swig_mark_arg(i + 1); +	    i++; +	  } else { +	    Swig_arg_error(); +	  } +	} else if ((strcmp(argv[i], "-noproxy") == 0)) { +	  Swig_mark_arg(i); +	  proxy_flag = false; +	} else if (strcmp(argv[i], "-oldvarnames") == 0) { +	  Swig_mark_arg(i); +	  old_variable_names = true; +	} else if (strcmp(argv[i], "-outfile") == 0) { +	  if (argv[i + 1]) { +	    output_file = NewString(""); +	    Printf(output_file, argv[i + 1]); +	    Swig_mark_arg(i); +	    Swig_mark_arg(i + 1); +	    i++; +	  } else { +	    Swig_arg_error(); +	  } +	} else if (strcmp(argv[i], "-help") == 0) { +	  Printf(stdout, "%s\n", usage); +	} +      } +    } + +    // Add a symbol to the parser for conditional compilation +    Preprocessor_define("SWIGCSHARP 1", 0); + +    // Add typemap definitions +    SWIG_typemap_lang("csharp"); +    SWIG_config_file("csharp.swg"); + +    allow_overloading(); +    Swig_interface_feature_enable(); +  } + +  /* --------------------------------------------------------------------- +   * top() +   * --------------------------------------------------------------------- */ + +  virtual int top(Node *n) { + +    // Get any options set in the module directive +    Node *optionsnode = Getattr(Getattr(n, "module"), "options"); + +    if (optionsnode) { +      if (Getattr(optionsnode, "imclassname")) +	imclass_name = Copy(Getattr(optionsnode, "imclassname")); +      /* check if directors are enabled for this module.  note: this  +       * is a "master" switch, without which no director code will be +       * emitted.  %feature("director") statements are also required +       * to enable directors for individual classes or methods. +       * +       * use %module(directors="1") modulename at the start of the  +       * interface file to enable director generation. +       */ +      if (Getattr(optionsnode, "directors")) { +	allow_directors(); +      } +      if (Getattr(optionsnode, "dirprot")) { +	allow_dirprot(); +      } +      allow_allprotected(GetFlag(optionsnode, "allprotected")); +    } + +    /* Initialize all of the output files */ +    String *outfile = Getattr(n, "outfile"); +    String *outfile_h = Getattr(n, "outfile_h"); + +    if (!outfile) { +      Printf(stderr, "Unable to determine outfile\n"); +      Exit(EXIT_FAILURE); +    } + +    f_begin = NewFile(outfile, "w", SWIG_output_files()); +    if (!f_begin) { +      FileErrorDisplay(outfile); +      Exit(EXIT_FAILURE); +    } + +    if (directorsEnabled()) { +      if (!outfile_h) { +        Printf(stderr, "Unable to determine outfile_h\n"); +        Exit(EXIT_FAILURE); +      } +      f_runtime_h = NewFile(outfile_h, "w", SWIG_output_files()); +      if (!f_runtime_h) { +	FileErrorDisplay(outfile_h); +	Exit(EXIT_FAILURE); +      } +    } + +    f_runtime = NewString(""); +    f_init = NewString(""); +    f_header = NewString(""); +    f_wrappers = NewString(""); +    f_directors_h = NewString(""); +    f_directors = NewString(""); + +    /* Register file targets with the SWIG file handler */ +    Swig_register_filebyname("header", f_header); +    Swig_register_filebyname("wrapper", f_wrappers); +    Swig_register_filebyname("begin", f_begin); +    Swig_register_filebyname("runtime", f_runtime); +    Swig_register_filebyname("init", f_init); +    Swig_register_filebyname("director", f_directors); +    Swig_register_filebyname("director_h", f_directors_h); + +    swig_types_hash = NewHash(); +    filenames_list = NewList(); + +    // Make the intermediary class and module class names. The intermediary class name can be set in the module directive. +    if (!imclass_name) { +      imclass_name = NewStringf("%sPINVOKE", Getattr(n, "name")); +      module_class_name = Copy(Getattr(n, "name")); +    } else { +      // Rename the module name if it is the same as intermediary class name - a backwards compatibility solution +      if (Cmp(imclass_name, Getattr(n, "name")) == 0) +	module_class_name = NewStringf("%sModule", Getattr(n, "name")); +      else +	module_class_name = Copy(Getattr(n, "name")); +    } + +    // module class and intermediary classes are always created +    if (!addSymbol(imclass_name, n)) +      return SWIG_ERROR; +    if (!addSymbol(module_class_name, n)) +      return SWIG_ERROR; + +    imclass_class_code = NewString(""); +    proxy_class_def = NewString(""); +    proxy_class_code = NewString(""); +    module_class_constants_code = NewString(""); +    imclass_baseclass = NewString(""); +    imclass_interfaces = NewString(""); +    imclass_class_modifiers = NewString(""); +    module_class_code = NewString(""); +    module_baseclass = NewString(""); +    module_interfaces = NewString(""); +    module_imports = NewString(""); +    module_class_modifiers = NewString(""); +    imclass_imports = NewString(""); +    imclass_cppcasts_code = NewString(""); +    director_connect_parms = NewString(""); +    upcasts_code = NewString(""); +    dmethods_seq = NewList(); +    dmethods_table = NewHash(); +    n_dmethods = 0; +    n_directors = 0; +    if (!dllimport) +      dllimport = Copy(module_class_name); + +    Swig_banner(f_begin); + +    Swig_obligatory_macros(f_runtime, "CSHARP"); + +    if (directorsEnabled()) { +      Printf(f_runtime, "#define SWIG_DIRECTORS\n"); + +      /* Emit initial director header and director code: */ +      Swig_banner(f_directors_h); +      Printf(f_directors_h, "\n"); +      Printf(f_directors_h, "#ifndef SWIG_%s_WRAP_H_\n", module_class_name); +      Printf(f_directors_h, "#define SWIG_%s_WRAP_H_\n\n", module_class_name); + +      Printf(f_directors, "\n\n"); +      Printf(f_directors, "/* ---------------------------------------------------\n"); +      Printf(f_directors, " * C++ director class methods\n"); +      Printf(f_directors, " * --------------------------------------------------- */\n\n"); +      if (outfile_h) { +	String *filename = Swig_file_filename(outfile_h); +	Printf(f_directors, "#include \"%s\"\n\n", filename); +	Delete(filename); +      } +    } + +    Printf(f_runtime, "\n"); +    if (namespce) { +      String *wrapper_name = NewStringf(""); +      Printf(wrapper_name, "CSharp_%s_%%f", namespce); +      Swig_name_register("wrapper", wrapper_name); +      Delete(wrapper_name); +    } +    else { +      Swig_name_register("wrapper", "CSharp_%f"); +    } + +    if (old_variable_names) { +      Swig_name_register("set", "set_%n%v"); +      Swig_name_register("get", "get_%n%v"); +    } + +    Printf(f_wrappers, "\n#ifdef __cplusplus\n"); +    Printf(f_wrappers, "extern \"C\" {\n"); +    Printf(f_wrappers, "#endif\n\n"); + +    /* Emit code */ +    Language::top(n); + +    if (directorsEnabled()) { +      // Insert director runtime into the f_runtime file (make it occur before %header section) +      Swig_insert_file("director_common.swg", f_runtime); +      Swig_insert_file("director.swg", f_runtime); +    } +    // Generate the intermediary class +    { +      File *f_im = getOutputFile(SWIG_output_directory(), imclass_name); + +      addOpenNamespace(0, f_im); + +      if (imclass_imports) +	Printf(f_im, "%s\n", imclass_imports); + +      if (Len(imclass_class_modifiers) > 0) +	Printf(f_im, "%s ", imclass_class_modifiers); +      Printf(f_im, "%s ", imclass_name); + +      if (imclass_baseclass && *Char(imclass_baseclass)) +	Printf(f_im, ": %s ", imclass_baseclass); +      if (Len(imclass_interfaces) > 0) +	Printv(f_im, "implements ", imclass_interfaces, " ", NIL); +      Printf(f_im, "{\n"); + +      // Add the intermediary class methods +      Replaceall(imclass_class_code, "$module", module_class_name); +      Replaceall(imclass_class_code, "$imclassname", imclass_name); +      Replaceall(imclass_class_code, "$dllimport", dllimport); +      Printv(f_im, imclass_class_code, NIL); +      Printv(f_im, imclass_cppcasts_code, NIL); + +      // Finish off the class +      Printf(f_im, "}\n"); +      addCloseNamespace(0, f_im); + +      if (f_im != f_single_out) +	Delete(f_im); +      f_im = NULL; +    } + +    // Generate the C# module class +    { +      File *f_module = getOutputFile(SWIG_output_directory(), module_class_name); + +      addOpenNamespace(0, f_module); + +      if (module_imports) +	Printf(f_module, "%s\n", module_imports); + +      if (Len(module_class_modifiers) > 0) +	Printf(f_module, "%s ", module_class_modifiers); +      Printf(f_module, "%s ", module_class_name); + +      if (module_baseclass && *Char(module_baseclass)) +	Printf(f_module, ": %s ", module_baseclass); +      if (Len(module_interfaces) > 0) +	Printv(f_module, "implements ", module_interfaces, " ", NIL); +      Printf(f_module, "{\n"); + +      Replaceall(module_class_code, "$module", module_class_name); +      Replaceall(module_class_constants_code, "$module", module_class_name); + +      Replaceall(module_class_code, "$imclassname", imclass_name); +      Replaceall(module_class_constants_code, "$imclassname", imclass_name); + +      Replaceall(module_class_code, "$dllimport", dllimport); +      Replaceall(module_class_constants_code, "$dllimport", dllimport); + +      // Add the wrapper methods +      Printv(f_module, module_class_code, NIL); + +      // Write out all the global constants +      Printv(f_module, module_class_constants_code, NIL); + +      // Finish off the class +      Printf(f_module, "}\n"); +      addCloseNamespace(0, f_module); + +      if (f_module != f_single_out) +	Delete(f_module); +      f_module = NULL; +    } + +    if (upcasts_code) +      Printv(f_wrappers, upcasts_code, NIL); + +    Printf(f_wrappers, "#ifdef __cplusplus\n"); +    Printf(f_wrappers, "}\n"); +    Printf(f_wrappers, "#endif\n"); + +    // Output a C# type wrapper class for each SWIG type +    for (Iterator swig_type = First(swig_types_hash); swig_type.key; swig_type = Next(swig_type)) { +      emitTypeWrapperClass(swig_type.key, swig_type.item); +    } + +    // Check for overwriting file problems on filesystems that are case insensitive +    Iterator it1; +    Iterator it2; +    for (it1 = First(filenames_list); it1.item; it1 = Next(it1)) { +      String *item1_lower = Swig_string_lower(it1.item); +      for (it2 = Next(it1); it2.item; it2 = Next(it2)) { +	String *item2_lower = Swig_string_lower(it2.item); +	if (it1.item && it2.item) { +	  if (Strcmp(item1_lower, item2_lower) == 0) { +	    Swig_warning(WARN_LANG_PORTABILITY_FILENAME, input_file, line_number, +			 "Portability warning: File %s will be overwritten by %s on case insensitive filesystems such as " +			 "Windows' FAT32 and NTFS unless the class/module name is renamed\n", it1.item, it2.item); +	  } +	} +	Delete(item2_lower); +      } +      Delete(item1_lower); +    } + +    Delete(swig_types_hash); +    swig_types_hash = NULL; +    Delete(filenames_list); +    filenames_list = NULL; +    Delete(imclass_name); +    imclass_name = NULL; +    Delete(imclass_class_code); +    imclass_class_code = NULL; +    Delete(proxy_class_def); +    proxy_class_def = NULL; +    Delete(proxy_class_code); +    proxy_class_code = NULL; +    Delete(module_class_constants_code); +    module_class_constants_code = NULL; +    Delete(imclass_baseclass); +    imclass_baseclass = NULL; +    Delete(imclass_interfaces); +    imclass_interfaces = NULL; +    Delete(imclass_class_modifiers); +    imclass_class_modifiers = NULL; +    Delete(module_class_name); +    module_class_name = NULL; +    Delete(module_class_code); +    module_class_code = NULL; +    Delete(module_baseclass); +    module_baseclass = NULL; +    Delete(module_interfaces); +    module_interfaces = NULL; +    Delete(module_imports); +    module_imports = NULL; +    Delete(module_class_modifiers); +    module_class_modifiers = NULL; +    Delete(imclass_imports); +    imclass_imports = NULL; +    Delete(imclass_cppcasts_code); +    imclass_cppcasts_code = NULL; +    Delete(upcasts_code); +    upcasts_code = NULL; +    Delete(dmethods_seq); +    dmethods_seq = NULL; +    Delete(dmethods_table); +    dmethods_table = NULL; +    Delete(namespce); +    namespce = NULL; +    n_dmethods = 0; + +    /* Close all of the files */ +    Dump(f_runtime, f_begin); +    Dump(f_header, f_begin); + +    if (directorsEnabled()) { +      Dump(f_directors, f_begin); +      Dump(f_directors_h, f_runtime_h); + +      Printf(f_runtime_h, "\n"); +      Printf(f_runtime_h, "#endif\n"); + +      Delete(f_runtime_h); +      f_runtime_h = NULL; +      Delete(f_directors); +      f_directors = NULL; +      Delete(f_directors_h); +      f_directors_h = NULL; +    } + +    if (f_single_out) { +      Dump(f_single_out, f_begin); +      Delete(f_single_out); +      f_single_out = NULL; +    } + +    Dump(f_wrappers, f_begin); +    Wrapper_pretty_print(f_init, f_begin); +    Delete(f_header); +    Delete(f_wrappers); +    Delete(f_init); +    Delete(f_runtime); +    Delete(f_begin); +    return SWIG_OK; +  } + +  /* ----------------------------------------------------------------------------- +   * emitBanner() +   * ----------------------------------------------------------------------------- */ + +  void emitBanner(File *f) { +    Printf(f, "//------------------------------------------------------------------------------\n"); +    Printf(f, "// <auto-generated />\n"); +    Printf(f, "//\n"); +    Swig_banner_target_lang(f, "//"); +    Printf(f, "//------------------------------------------------------------------------------\n\n"); +  } + +  /* ----------------------------------------------------------------------------- +   * getOutputFile() +   * +   * Prepares a File object by creating the file in the file system and +   * writing the banner for auto-generated files to it (emitBanner). +   * If '-outfile' is provided (single file mode) the supplied parameters will +   * be ignored and the returned file will always be: +   *  <outdir>/<outfile> +   * Otherwise the file will be: +   *  <dir>/<name>.cs +   * ----------------------------------------------------------------------------- */ + +  File *getOutputFile(const String *dir, const String *name) { +    if (output_file) { +      if (!f_single_out) { +	String *filen = NewStringf("%s%s", SWIG_output_directory(), output_file); +	f_single_out = NewFile(filen, "w", SWIG_output_files()); +	if (!f_single_out) { +	  FileErrorDisplay(filen); +	  Exit(EXIT_FAILURE); +	} +	Append(filenames_list, Copy(filen)); +	Delete(filen); +	filen = NULL; + +	emitBanner(f_single_out); +      } +      return f_single_out; +    } else { +      String *filen = NewStringf("%s%s.cs", dir, name); +      File *f = NewFile(filen, "w", SWIG_output_files()); +      if (!f) { +	FileErrorDisplay(filen); +	Exit(EXIT_FAILURE); +      } +      Append(filenames_list, Copy(filen)); +      Delete(filen); +      filen = NULL; + +      emitBanner(f); +      return f; +    } +  } + +  /*----------------------------------------------------------------------- +   * Add new director upcall signature +   *----------------------------------------------------------------------*/ + +  UpcallData *addUpcallMethod(String *imclass_method, String *class_method, String *decl, String *overloaded_name) { +    String *key = NewStringf("%s|%s", imclass_method, decl); + +    ++curr_class_dmethod; + +    String *class_methodidx = NewStringf("%d", n_dmethods - first_class_dmethod); +    n_dmethods++; + +    Hash *new_udata = NewHash(); +    Append(dmethods_seq, new_udata); +    Setattr(dmethods_table, key, new_udata); + +    Setattr(new_udata, "method", Copy(class_method)); +    Setattr(new_udata, "class_methodidx", class_methodidx); +    Setattr(new_udata, "decl", Copy(decl)); +    Setattr(new_udata, "overname", Copy(overloaded_name)); + +    Delete(key); +    return new_udata; +  } + +  /*----------------------------------------------------------------------- +   * Get director upcall signature +   *----------------------------------------------------------------------*/ + +  /* +     UpcallData * getUpcallMethodData(String *director_class, String *decl) { +     String             *key = NewStringf("%s|%s", director_class, decl); +     UpcallData         *udata = Getattr(dmethods_table, key); + +     Delete(key); +     return udata; +     } +   */ + +  /* ---------------------------------------------------------------------- +   * nativeWrapper() +   * ---------------------------------------------------------------------- */ + +  virtual int nativeWrapper(Node *n) { +    String *wrapname = Getattr(n, "wrap:name"); + +    if (!addSymbol(wrapname, n, imclass_name)) +      return SWIG_ERROR; + +    if (Getattr(n, "type")) { +      Swig_save("nativeWrapper", n, "name", NIL); +      Setattr(n, "name", wrapname); +      native_function_flag = true; +      functionWrapper(n); +      Swig_restore(n); +      native_function_flag = false; +    } else { +      Swig_error(input_file, line_number, "No return type for %%native method %s.\n", Getattr(n, "wrap:name")); +    } + +    return SWIG_OK; +  } + +  /* ---------------------------------------------------------------------- +   * functionWrapper() +   * ---------------------------------------------------------------------- */ + +  virtual int functionWrapper(Node *n) { +    String *symname = Getattr(n, "sym:name"); +    SwigType *t = Getattr(n, "type"); +    ParmList *l = Getattr(n, "parms"); +    String *tm; +    Parm *p; +    int i; +    String *c_return_type = NewString(""); +    String *im_return_type = NewString(""); +    String *cleanup = NewString(""); +    String *outarg = NewString(""); +    String *body = NewString(""); +    String *im_outattributes = 0; +    int num_arguments = 0; +    bool is_void_return; +    String *overloaded_name = getOverloadedName(n); + +    if (!Getattr(n, "sym:overloaded")) { +      if (!addSymbol(symname, n, imclass_name)) +	return SWIG_ERROR; +    } + +    /* +       The rest of this function deals with generating the intermediary class wrapper function (that wraps +       a c/c++ function) and generating the PInvoke c code. Each C# wrapper function has a  +       matching PInvoke c function call. +     */ + +    // A new wrapper function object +    Wrapper *f = NewWrapper(); + +    // Make a wrapper name for this function +    String *wname = Swig_name_wrapper(overloaded_name); + +    /* Attach the non-standard typemaps to the parameter list. */ +    Swig_typemap_attach_parms("ctype", l, f); +    Swig_typemap_attach_parms("imtype", l, f); + +    /* Get return types */ +    if ((tm = Swig_typemap_lookup("ctype", n, "", 0))) { +      String *ctypeout = Getattr(n, "tmap:ctype:out");	// the type in the ctype typemap's out attribute overrides the type in the typemap +      if (ctypeout) +	tm = ctypeout; +      Printf(c_return_type, "%s", tm); +    } else { +      Swig_warning(WARN_CSHARP_TYPEMAP_CTYPE_UNDEF, input_file, line_number, "No ctype typemap defined for %s\n", SwigType_str(t, 0)); +    } + +    if ((tm = Swig_typemap_lookup("imtype", n, "", 0))) { +      String *imtypeout = Getattr(n, "tmap:imtype:out");	// the type in the imtype typemap's out attribute overrides the type in the typemap +      if (imtypeout) +	tm = imtypeout; +      Printf(im_return_type, "%s", tm); +      im_outattributes = Getattr(n, "tmap:imtype:outattributes"); +    } else { +      Swig_warning(WARN_CSHARP_TYPEMAP_CSTYPE_UNDEF, input_file, line_number, "No imtype typemap defined for %s\n", SwigType_str(t, 0)); +    } + +    is_void_return = (Cmp(c_return_type, "void") == 0); +    if (!is_void_return) +      Wrapper_add_localv(f, "jresult", c_return_type, "jresult", NIL); + +    Printv(f->def, " SWIGEXPORT ", c_return_type, " SWIGSTDCALL ", wname, "(", NIL); + +    // Emit all of the local variables for holding arguments. +    emit_parameter_variables(l, f); + +    /* Attach the standard typemaps */ +    emit_attach_parmmaps(l, f); + +    // Parameter overloading +    Setattr(n, "wrap:parms", l); +    Setattr(n, "wrap:name", wname); + +    // Wrappers not wanted for some methods where the parameters cannot be overloaded in C# +    if (Getattr(n, "sym:overloaded")) { +      // Emit warnings for the few cases that can't be overloaded in C# and give up on generating wrapper +      Swig_overload_check(n); +      if (Getattr(n, "overload:ignore")) { +	DelWrapper(f); +	return SWIG_OK; +      } +    } + +    Printv(imclass_class_code, "\n  [global::System.Runtime.InteropServices.DllImport(\"", dllimport, "\", EntryPoint=\"", wname, "\")]\n", NIL); + +    if (im_outattributes) +      Printf(imclass_class_code, "  %s\n", im_outattributes); + +    Printf(imclass_class_code, "  public static extern %s %s(", im_return_type, overloaded_name); + + +    /* Get number of required and total arguments */ +    num_arguments = emit_num_arguments(l); +    int gencomma = 0; + +    // Now walk the function parameter list and generate code to get arguments +    for (i = 0, p = l; i < num_arguments; i++) { + +      while (checkAttribute(p, "tmap:in:numinputs", "0")) { +	p = Getattr(p, "tmap:in:next"); +      } + +      SwigType *pt = Getattr(p, "type"); +      String *ln = Getattr(p, "lname"); +      String *im_param_type = NewString(""); +      String *c_param_type = NewString(""); +      String *arg = NewString(""); + +      Printf(arg, "j%s", ln); + +      /* Get the ctype types of the parameter */ +      if ((tm = Getattr(p, "tmap:ctype"))) { +	Printv(c_param_type, tm, NIL); +      } else { +	Swig_warning(WARN_CSHARP_TYPEMAP_CTYPE_UNDEF, input_file, line_number, "No ctype typemap defined for %s\n", SwigType_str(pt, 0)); +      } + +      /* Get the intermediary class parameter types of the parameter */ +      if ((tm = Getattr(p, "tmap:imtype"))) { +	const String *inattributes = Getattr(p, "tmap:imtype:inattributes"); +	Printf(im_param_type, "%s%s", inattributes ? inattributes : empty_string, tm); +      } else { +	Swig_warning(WARN_CSHARP_TYPEMAP_CSTYPE_UNDEF, input_file, line_number, "No imtype typemap defined for %s\n", SwigType_str(pt, 0)); +      } + +      /* Add parameter to intermediary class method */ +      if (gencomma) +	Printf(imclass_class_code, ", "); +      Printf(imclass_class_code, "%s %s", im_param_type, arg); + +      // Add parameter to C function +      Printv(f->def, gencomma ? ", " : "", c_param_type, " ", arg, NIL); + +      gencomma = 1; + +      // Get typemap for this argument +      if ((tm = Getattr(p, "tmap:in"))) { +	canThrow(n, "in", p); +	Replaceall(tm, "$arg", arg);	/* deprecated? */ +	Replaceall(tm, "$input", arg); +	Setattr(p, "emit:input", arg); +	Printf(f->code, "%s\n", tm); +	p = Getattr(p, "tmap:in:next"); +      } else { +	Swig_warning(WARN_TYPEMAP_IN_UNDEF, input_file, line_number, "Unable to use type %s as a function argument.\n", SwigType_str(pt, 0)); +	p = nextSibling(p); +      } +      Delete(im_param_type); +      Delete(c_param_type); +      Delete(arg); +    } + +    /* Insert constraint checking code */ +    for (p = l; p;) { +      if ((tm = Getattr(p, "tmap:check"))) { +	canThrow(n, "check", p); +	Replaceall(tm, "$arg", Getattr(p, "emit:input"));	/* deprecated? */ +	Replaceall(tm, "$input", Getattr(p, "emit:input")); +	Printv(f->code, tm, "\n", NIL); +	p = Getattr(p, "tmap:check:next"); +      } else { +	p = nextSibling(p); +      } +    } + +    /* Insert cleanup code */ +    for (p = l; p;) { +      if ((tm = Getattr(p, "tmap:freearg"))) { +	canThrow(n, "freearg", p); +	Replaceall(tm, "$arg", Getattr(p, "emit:input"));	/* deprecated? */ +	Replaceall(tm, "$input", Getattr(p, "emit:input")); +	Printv(cleanup, tm, "\n", NIL); +	p = Getattr(p, "tmap:freearg:next"); +      } else { +	p = nextSibling(p); +      } +    } + +    /* Insert argument output code */ +    for (p = l; p;) { +      if ((tm = Getattr(p, "tmap:argout"))) { +	canThrow(n, "argout", p); +	Replaceall(tm, "$arg", Getattr(p, "emit:input"));	/* deprecated? */ +	Replaceall(tm, "$result", "jresult"); +	Replaceall(tm, "$input", Getattr(p, "emit:input")); +	Printv(outarg, tm, "\n", NIL); +	p = Getattr(p, "tmap:argout:next"); +      } else { +	p = nextSibling(p); +      } +    } + +    // Look for usage of throws typemap and the canthrow flag +    ParmList *throw_parm_list = NULL; +    if ((throw_parm_list = Getattr(n, "catchlist"))) { +      Swig_typemap_attach_parms("throws", throw_parm_list, f); +      for (p = throw_parm_list; p; p = nextSibling(p)) { +	if (Getattr(p, "tmap:throws")) { +	  canThrow(n, "throws", p); +	} +      } +    } + +    String *null_attribute = 0; +    // Now write code to make the function call +    if (!native_function_flag) { + +      Swig_director_emit_dynamic_cast(n, f); +      String *actioncode = emit_action(n); + +      /* Return value if necessary  */ +      if ((tm = Swig_typemap_lookup_out("out", n, Swig_cresult_name(), f, actioncode))) { +	canThrow(n, "out", n); +	Replaceall(tm, "$result", "jresult"); + +        if (GetFlag(n, "feature:new")) +          Replaceall(tm, "$owner", "1"); +        else +          Replaceall(tm, "$owner", "0"); + +	Printf(f->code, "%s", tm); +	null_attribute = Getattr(n, "tmap:out:null"); +	if (Len(tm)) +	  Printf(f->code, "\n"); +      } else { +	Swig_warning(WARN_TYPEMAP_OUT_UNDEF, input_file, line_number, "Unable to use return type %s in function %s.\n", SwigType_str(t, 0), Getattr(n, "name")); +      } +      emit_return_variable(n, t, f); +    } + +    /* Output argument output code */ +    Printv(f->code, outarg, NIL); + +    /* Output cleanup code */ +    Printv(f->code, cleanup, NIL); + +    /* Look to see if there is any newfree cleanup code */ +    if (GetFlag(n, "feature:new")) { +      if ((tm = Swig_typemap_lookup("newfree", n, Swig_cresult_name(), 0))) { +	canThrow(n, "newfree", n); +	Printf(f->code, "%s\n", tm); +      } +    } + +    /* See if there is any return cleanup code */ +    if (!native_function_flag) { +      if ((tm = Swig_typemap_lookup("ret", n, Swig_cresult_name(), 0))) { +	canThrow(n, "ret", n); +	Printf(f->code, "%s\n", tm); +      } +    } + +    /* Finish C function and intermediary class function definitions */ +    Printf(imclass_class_code, ")"); +    Printf(imclass_class_code, ";\n"); + +    Printf(f->def, ") {"); + +    if (!is_void_return) +      Printv(f->code, "    return jresult;\n", NIL); +    Printf(f->code, "}\n"); + +    /* Substitute the cleanup code */ +    Replaceall(f->code, "$cleanup", cleanup); + +    /* Substitute the function name */ +    Replaceall(f->code, "$symname", symname); + +    /* Contract macro modification */ +    if (Replaceall(f->code, "SWIG_contract_assert(", "SWIG_contract_assert($null, ") > 0) { +      Setattr(n, "csharp:canthrow", "1"); +    } + +    if (!null_attribute) +      Replaceall(f->code, "$null", "0"); +    else +      Replaceall(f->code, "$null", null_attribute); + +    /* Dump the function out */ +    if (!native_function_flag) { +      Wrapper_print(f, f_wrappers); + +      // Handle %csexception which sets the canthrow attribute +      if (Getattr(n, "feature:except:canthrow")) +	Setattr(n, "csharp:canthrow", "1"); + +      // A very simple check (it is not foolproof) to help typemap/feature writers for +      // throwing C# exceptions from unmanaged code. It checks for the common methods which +      // set a pending C# exception... the 'canthrow' typemap/feature attribute must be set +      // so that code which checks for pending exceptions is added in the C# proxy method. +      if (!Getattr(n, "csharp:canthrow")) { +	if (Strstr(f->code, "SWIG_exception")) { +	  Swig_warning(WARN_CSHARP_CANTHROW, input_file, line_number, +		       "Unmanaged code contains a call to SWIG_exception and C# code does not handle pending exceptions via the canthrow attribute.\n"); +	} else if (Strstr(f->code, "SWIG_CSharpSetPendingException")) { +	  Swig_warning(WARN_CSHARP_CANTHROW, input_file, line_number, +		       "Unmanaged code contains a call to a SWIG_CSharpSetPendingException method and C# code does not handle pending exceptions via the canthrow attribute.\n"); +	} +      } +    } + +    if (!(proxy_flag && is_wrapping_class()) && !enum_constant_flag) { +      moduleClassFunctionHandler(n); +    } + +    /*  +     * Generate the proxy class properties for public member variables. +     * Not for enums and constants. +     */ +    if (proxy_flag && wrapping_member_flag && !enum_constant_flag) { +      // Capitalize the first letter in the variable in the getter/setter function name +      bool getter_flag = Cmp(symname, Swig_name_set(getNSpace(), Swig_name_member(0, getClassPrefix(), variable_name))) != 0; + +      String *getter_setter_name = NewString(""); +      if (!getter_flag) +	Printf(getter_setter_name, "set"); +      else +	Printf(getter_setter_name, "get"); +      Putc(toupper((int) *Char(variable_name)), getter_setter_name); +      Printf(getter_setter_name, "%s", Char(variable_name) + 1); + +      Setattr(n, "proxyfuncname", getter_setter_name); +      Setattr(n, "imfuncname", symname); + +      proxyClassFunctionHandler(n); +      Delete(getter_setter_name); +    } + +    Delete(c_return_type); +    Delete(im_return_type); +    Delete(cleanup); +    Delete(outarg); +    Delete(body); +    Delete(overloaded_name); +    DelWrapper(f); +    return SWIG_OK; +  } + +  /* ----------------------------------------------------------------------- +   * variableWrapper() +   * ----------------------------------------------------------------------- */ + +  virtual int variableWrapper(Node *n) { +    Language::variableWrapper(n); +    return SWIG_OK; +  } + +  /* ----------------------------------------------------------------------- +   * globalvariableHandler() +   * ------------------------------------------------------------------------ */ + +  virtual int globalvariableHandler(Node *n) { + +    generate_property_declaration_flag = true; +    variable_name = Getattr(n, "sym:name"); +    global_variable_flag = true; +    int ret = Language::globalvariableHandler(n); +    global_variable_flag = false; +    generate_property_declaration_flag = false; + +    if (proxy_flag) { +      Printf(module_class_code, "\n  }\n\n"); +    } + +    return ret; +  } +   +  String *getCurrentScopeName(String *nspace) { +    String *scope = 0; +    if (nspace || getCurrentClass()) { +      scope = NewString(""); +      if (nspace) +	Printf(scope, "%s", nspace); +      if (Node *cls = getCurrentClass()) { +	if (Node *outer = Getattr(cls, "nested:outer")) { +	  String *outerClassesPrefix = Copy(Getattr(outer, "sym:name")); +	  for (outer = Getattr(outer, "nested:outer"); outer != 0; outer = Getattr(outer, "nested:outer")) { +	    Push(outerClassesPrefix, "."); +	    Push(outerClassesPrefix, Getattr(outer, "sym:name")); +	  } +	  Printv(scope, nspace ? "." : "", outerClassesPrefix, ".", proxy_class_name, NIL); +	  Delete(outerClassesPrefix); +	} else +	  Printv(scope, nspace ? "." : "", proxy_class_name, NIL); +      } +    } +    return scope; +  } + +  /* ---------------------------------------------------------------------- +   * enumDeclaration() +   * +   * C/C++ enums can be mapped in one of 4 ways, depending on the cs:enum feature specified: +   * 1) Simple enums - simple constant within the proxy class or module class +   * 2) Typeunsafe enums - simple constant in a C# class (class named after the c++ enum name) +   * 3) Typesafe enum - typesafe enum pattern (class named after the c++ enum name) +   * 4) Proper enums - proper C# enum +   * Anonymous enums always default to 1) +   * ---------------------------------------------------------------------- */ + +  virtual int enumDeclaration(Node *n) { + +    if (!ImportMode) { +      if (getCurrentClass() && (cplus_mode != PUBLIC)) +	return SWIG_NOWRAP; + +      String *nspace = Getattr(n, "sym:nspace"); // NSpace/getNSpace() only works during Language::enumDeclaration call +      if (proxy_flag && !is_wrapping_class()) { +	// Global enums / enums in a namespace +	assert(!full_imclass_name); + +	if (!nspace) { +	  full_imclass_name = NewStringf("%s", imclass_name); +	} else { +	  if (namespce) { +	    full_imclass_name = NewStringf("%s.%s", namespce, imclass_name); +	  } else { +	    full_imclass_name = NewStringf("%s", imclass_name); +	  } +	} +      } + +      enum_code = NewString(""); +      String *symname = Getattr(n, "sym:name"); +      String *constants_code = (proxy_flag && is_wrapping_class())? proxy_class_constants_code : module_class_constants_code; +      EnumFeature enum_feature = decodeEnumFeature(n); +      String *typemap_lookup_type = Getattr(n, "name"); + +      if ((enum_feature != SimpleEnum) && symname && typemap_lookup_type) { +	// Wrap (non-anonymous) C/C++ enum within a typesafe, typeunsafe or proper C# enum + +	String *scope = getCurrentScopeName(nspace); +	if (!addSymbol(symname, n, scope)) +	  return SWIG_ERROR; + +	// Pure C# baseclass and interfaces +	const String *pure_baseclass = typemapLookup(n, "csbase", typemap_lookup_type, WARN_NONE); +	const String *pure_interfaces = typemapLookup(n, "csinterfaces", typemap_lookup_type, WARN_NONE); + +	// Class attributes +	const String *csattributes = typemapLookup(n, "csattributes", typemap_lookup_type, WARN_NONE); +	if (csattributes && *Char(csattributes)) +	  Printf(enum_code, "%s\n", csattributes); + +	// Emit the enum +	Printv(enum_code, typemapLookup(n, "csclassmodifiers", typemap_lookup_type, WARN_CSHARP_TYPEMAP_CLASSMOD_UNDEF),	// Class modifiers (enum modifiers really) +	       " ", symname, (*Char(pure_baseclass) || *Char(pure_interfaces)) ? " : " : "", pure_baseclass, ((*Char(pure_baseclass)) && *Char(pure_interfaces)) ?	// Interfaces +	       ", " : "", pure_interfaces, " {\n", NIL); +	Delete(scope); +      } else { +	// Wrap C++ enum with integers - just indicate start of enum with a comment, no comment for anonymous enums of any sort +	if (symname && !Getattr(n, "unnamedinstance")) +	  Printf(constants_code, "  // %s \n", symname); +      } + +      // Emit each enum item +      Language::enumDeclaration(n); + +      if ((enum_feature != SimpleEnum) && symname && typemap_lookup_type) { +	// Wrap (non-anonymous) C/C++ enum within a typesafe, typeunsafe or proper C# enum +	// Finish the enum declaration +	// Typemaps are used to generate the enum definition in a similar manner to proxy classes. +	Printv(enum_code, (enum_feature == ProperEnum) ? "\n" : typemapLookup(n, "csbody", typemap_lookup_type, WARN_CSHARP_TYPEMAP_CSBODY_UNDEF),	// main body of class +	       typemapLookup(n, "cscode", typemap_lookup_type, WARN_NONE),	// extra C# code +	       "}", NIL); + +	Replaceall(enum_code, "$csclassname", symname); + +	// Substitute $enumvalues - intended usage is for typesafe enums +	if (Getattr(n, "enumvalues")) +	  Replaceall(enum_code, "$enumvalues", Getattr(n, "enumvalues")); +	else +	  Replaceall(enum_code, "$enumvalues", ""); + +	if (proxy_flag && is_wrapping_class()) { +	  // Enums defined within the C++ class are defined within the proxy class + +	  // Add extra indentation +	  Replaceall(enum_code, "\n", "\n  "); +	  Replaceall(enum_code, "  \n", "\n"); + +	  Printv(proxy_class_constants_code, "  ", enum_code, "\n\n", NIL); +	} else { +	  // Global enums are defined in their own file +	  String *output_directory = outputDirectory(nspace); +	  File *f_enum = getOutputFile(output_directory, symname); + +	  addOpenNamespace(nspace, f_enum); + +	  Printv(f_enum, typemapLookup(n, "csimports", typemap_lookup_type, WARN_NONE), // Import statements +		 "\n", enum_code, "\n", NIL); + +	  addCloseNamespace(nspace, f_enum); +	  if (f_enum != f_single_out) +	    Delete(f_enum); +	  f_enum = NULL; +	  Delete(output_directory); +	} +      } else { +	// Wrap C++ enum with simple constant +	Printf(enum_code, "\n"); +	if (proxy_flag && is_wrapping_class()) +	  Printv(proxy_class_constants_code, enum_code, NIL); +	else +	  Printv(module_class_constants_code, enum_code, NIL); +      } + +      Delete(enum_code); +      enum_code = NULL; + +      if (proxy_flag && !is_wrapping_class()) { +	Delete(full_imclass_name); +	full_imclass_name = 0; +      } +    } +    return SWIG_OK; +  } + +  /* ---------------------------------------------------------------------- +   * enumvalueDeclaration() +   * ---------------------------------------------------------------------- */ + +  virtual int enumvalueDeclaration(Node *n) { +    if (getCurrentClass() && (cplus_mode != PUBLIC)) +      return SWIG_NOWRAP; + +    Swig_require("enumvalueDeclaration", n, "*name", "?value", NIL); +    String *symname = Getattr(n, "sym:name"); +    String *value = Getattr(n, "value"); +    String *name = Getattr(n, "name"); +    Node *parent = parentNode(n); +    int unnamedinstance = GetFlag(parent, "unnamedinstance"); +    String *parent_name = Getattr(parent, "name"); +    String *nspace = getNSpace(); +    String *newsymname = 0; +    String *tmpValue; + +    // Strange hack from parent method +    if (value) +      tmpValue = NewString(value); +    else +      tmpValue = NewString(name); +    // Note that this is used in enumValue() amongst other places +    Setattr(n, "value", tmpValue); + +    // Deal with enum values that are not int +    int swigtype = SwigType_type(Getattr(n, "type")); +    if (swigtype == T_BOOL) { +      const char *val = Equal(Getattr(n, "enumvalue"), "true") ? "1" : "0"; +      Setattr(n, "enumvalue", val); +    } else if (swigtype == T_CHAR) { +      String *val = NewStringf("'%(hexescape)s'", Getattr(n, "enumvalue")); +      Setattr(n, "enumvalue", val); +      Delete(val); +    } + +    { +      EnumFeature enum_feature = decodeEnumFeature(parent); + +      if ((enum_feature == SimpleEnum) && GetFlag(parent, "scopedenum")) { +	newsymname = Swig_name_member(0, Getattr(parent, "sym:name"), symname); +	symname = newsymname; +      } + +      // Add to language symbol table +      String *scope = 0; +      if (unnamedinstance || !parent_name || enum_feature == SimpleEnum) { +	String *enumClassPrefix = getEnumClassPrefix(); +	if (enumClassPrefix) { +	  scope = NewString(""); +	  if (nspace) +	    Printf(scope, "%s.", nspace); +	  Printf(scope, "%s", enumClassPrefix); +	} else { +	  scope = Copy(module_class_name); +	} +      } else { +	scope = getCurrentScopeName(nspace); +	if (!scope) +	  scope = Copy(Getattr(parent, "sym:name")); +	else +	  Printf(scope, ".%s", Getattr(parent, "sym:name")); +      } +      if (!addSymbol(symname, n, scope)) +	return SWIG_ERROR; + +      const String *csattributes = Getattr(n, "feature:cs:attributes"); + +      if ((enum_feature == ProperEnum) && parent_name && !unnamedinstance) { +	// Wrap (non-anonymous) C/C++ enum with a proper C# enum +	// Emit the enum item. +	if (!GetFlag(n, "firstenumitem")) +	  Printf(enum_code, ",\n"); + +	if (csattributes) +	  Printf(enum_code, "  %s\n", csattributes); + +	Printf(enum_code, "  %s", symname); + +	// Check for the %csconstvalue feature +	String *value = Getattr(n, "feature:cs:constvalue"); + +	// Note that the enum value must be a true constant and cannot be set from a PINVOKE call, thus no support for %csconst(0) +	value = value ? value : Getattr(n, "enumvalue"); +	if (value) { +	  Printf(enum_code, " = %s", value); +	} +      } else { +	// Wrap C/C++ enums with constant integers or use the typesafe enum pattern +	SwigType *typemap_lookup_type = parent_name ? parent_name : NewString("enum "); +	Setattr(n, "type", typemap_lookup_type); +	const String *tm = typemapLookup(n, "cstype", typemap_lookup_type, WARN_CSHARP_TYPEMAP_CSWTYPE_UNDEF); + +	String *return_type = Copy(tm); +	substituteClassname(typemap_lookup_type, return_type); +        const String *methodmods = Getattr(n, "feature:cs:methodmodifiers"); +        methodmods = methodmods ? methodmods : (is_public(n) ? public_string : protected_string); + +	if (csattributes) +	  Printf(enum_code, "  %s\n", csattributes); + +	if ((enum_feature == TypesafeEnum) && parent_name && !unnamedinstance) { +	  // Wrap (non-anonymous) enum using the typesafe enum pattern +	  if (Getattr(n, "enumvalue")) { +	    String *value = enumValue(n); +	    Printf(enum_code, "  %s static readonly %s %s = new %s(\"%s\", %s);\n", methodmods, return_type, symname, return_type, symname, value); +	    Delete(value); +	  } else { +	    Printf(enum_code, "  %s static readonly %s %s = new %s(\"%s\");\n", methodmods, return_type, symname, return_type, symname); +	  } +	} else { +	  // Simple integer constants +	  // Note these are always generated for anonymous enums, no matter what enum_feature is specified +	  // Code generated is the same for SimpleEnum and TypeunsafeEnum -> the class it is generated into is determined later + +	  // The %csconst feature determines how the constant value is obtained +	  int const_feature_flag = GetFlag(n, "feature:cs:const"); + +	  const char *const_readonly = const_feature_flag ? "const" : "static readonly"; +	  String *value = enumValue(n); +	  Printf(enum_code, "  %s %s %s %s = %s;\n", methodmods, const_readonly, return_type, symname, value); +	  Delete(value); +	} +	Delete(return_type); +      } + +      // Add the enum value to the comma separated list being constructed in the enum declaration. +      String *enumvalues = Getattr(parent, "enumvalues"); +      if (!enumvalues) +	Setattr(parent, "enumvalues", Copy(symname)); +      else +	Printv(enumvalues, ", ", symname, NIL); +      Delete(scope); +    } + +    Delete(newsymname); +    Delete(tmpValue); +    Swig_restore(n); +    return SWIG_OK; +  } + +  /* ----------------------------------------------------------------------- +   * constantWrapper() +   * Used for wrapping constants - #define or %constant. +   * Also for inline initialised const static primitive type member variables (short, int, double, enums etc). +   * C# static const variables are generated for these. +   * If the %csconst(1) feature is used then the C constant value is used to initialise the C# const variable. +   * If not, a PINVOKE method is generated to get the C constant value for initialisation of the C# const variable. +   * However, if the %csconstvalue feature is used, it overrides all other ways to generate the initialisation. +   * Also note that this method might be called for wrapping enum items (when the enum is using %csconst(0)). +   * ------------------------------------------------------------------------ */ + +  virtual int constantWrapper(Node *n) { +    String *symname = Getattr(n, "sym:name"); +    SwigType *t = Getattr(n, "type"); +    SwigType *valuetype = Getattr(n, "valuetype"); +    ParmList *l = Getattr(n, "parms"); +    String *tm; +    String *return_type = NewString(""); +    String *constants_code = NewString(""); +    Swig_save("constantWrapper", n, "value", NIL); +    Swig_save("constantWrapper", n, "tmap:ctype:out", "tmap:imtype:out", "tmap:cstype:out", "tmap:out:null", "tmap:imtype:outattributes", "tmap:cstype:outattributes", NIL); + +    bool is_enum_item = (Cmp(nodeType(n), "enumitem") == 0); + +    const String *itemname = (proxy_flag && wrapping_member_flag) ? variable_name : symname; +    if (!is_enum_item) { +      String *scope = 0; +      if (proxy_class_name) { +	String *nspace = getNSpace(); +	scope = NewString(""); +	if (nspace) +	  Printf(scope, "%s.", nspace); +	Printf(scope, "%s", proxy_class_name); +      } else { +	scope = Copy(module_class_name); +      } +      if (!addSymbol(itemname, n, scope)) +	return SWIG_ERROR; +      Delete(scope); +    } + +    // The %csconst feature determines how the constant value is obtained +    int const_feature_flag = GetFlag(n, "feature:cs:const"); + +    /* Adjust the enum type for the Swig_typemap_lookup. +     * We want the same jstype typemap for all the enum items so we use the enum type (parent node). */ +    if (is_enum_item) { +      t = Getattr(parentNode(n), "enumtype"); +      Setattr(n, "type", t); +    } + +    /* Attach the non-standard typemaps to the parameter list. */ +    Swig_typemap_attach_parms("cstype", l, NULL); + +    /* Get C# return types */ +    bool classname_substituted_flag = false; + +    if ((tm = Swig_typemap_lookup("cstype", n, "", 0))) { +      String *cstypeout = Getattr(n, "tmap:cstype:out");	// the type in the cstype typemap's out attribute overrides the type in the typemap +      if (cstypeout) +	tm = cstypeout; +      classname_substituted_flag = substituteClassname(t, tm); +      Printf(return_type, "%s", tm); +    } else { +      Swig_warning(WARN_CSHARP_TYPEMAP_CSWTYPE_UNDEF, input_file, line_number, "No cstype typemap defined for %s\n", SwigType_str(t, 0)); +    } + +    // Default (octal) escaping is no good - change to hex escaped value +    String *hexescaped_value = Getattr(n, "rawvalue") ? NewStringf("%(hexescape)s", Getattr(n, "rawvalue")) : 0; +    // Add the stripped quotes back in +    String *new_value = NewString(""); +    if (SwigType_type(t) == T_STRING) { +      Printf(new_value, "\"%s\"", hexescaped_value ? hexescaped_value : Copy(Getattr(n, "value"))); +      Setattr(n, "value", new_value); +    } else if (SwigType_type(t) == T_CHAR) { +      Printf(new_value, "\'%s\'", hexescaped_value ? hexescaped_value : Copy(Getattr(n, "value"))); +      Setattr(n, "value", new_value); +    } + +    const String *outattributes = Getattr(n, "tmap:cstype:outattributes"); +    if (outattributes) +      Printf(constants_code, "  %s\n", outattributes); + +    const String *methodmods = Getattr(n, "feature:cs:methodmodifiers"); +    methodmods = methodmods ? methodmods : (is_public(n) ? public_string : protected_string); + +    Printf(constants_code, "  %s %s %s %s = ", methodmods, (const_feature_flag ? "const" : "static readonly"), return_type, itemname); + +    // Check for the %csconstvalue feature +    String *value = Getattr(n, "feature:cs:constvalue"); + +    if (value) { +      Printf(constants_code, "%s;\n", value); +    } else if (!const_feature_flag) { +      // Default enum and constant handling will work with any type of C constant and initialises the C# variable from C through a PINVOKE call. + +      if (classname_substituted_flag) { +	if (SwigType_isenum(t)) { +	  // This handles wrapping of inline initialised const enum static member variables (not when wrapping enum items - ignored later on) +	  Printf(constants_code, "(%s)%s.%s();\n", return_type, full_imclass_name ? full_imclass_name : imclass_name, Swig_name_get(getNSpace(), symname)); +	} else { +	  // This handles function pointers using the %constant directive +	  Printf(constants_code, "new %s(%s.%s(), false);\n", return_type, full_imclass_name ? full_imclass_name : imclass_name, Swig_name_get(getNSpace(), symname)); +	} +      } else { +	Printf(constants_code, "%s.%s();\n", full_imclass_name ? full_imclass_name : imclass_name, Swig_name_get(getNSpace(), symname)); +      } + +      // Each constant and enum value is wrapped with a separate PInvoke function call +      SetFlag(n, "feature:immutable"); +      enum_constant_flag = true; +      variableWrapper(n); +      enum_constant_flag = false; +    } else { +      // Alternative constant handling will use the C syntax to make a true C# constant and hope that it compiles as C# code +      if (Getattr(n, "wrappedasconstant")) { +	if (SwigType_type(t) == T_CHAR) { +	  if (SwigType_type(valuetype) == T_CHAR) +	    Printf(constants_code, "\'%(hexescape)s\';\n", Getattr(n, "staticmembervariableHandler:value")); +	  else +	    Printf(constants_code, "(char)%s;\n", Getattr(n, "staticmembervariableHandler:value")); +	} else { +          Printf(constants_code, "%s;\n", Getattr(n, "staticmembervariableHandler:value")); +	} +      } else { +        Printf(constants_code, "%s;\n", Getattr(n, "value")); +      } +    } + +    // Emit the generated code to appropriate place +    // Enums only emit the intermediate and PINVOKE methods, so no proxy or module class wrapper methods needed +    if (!is_enum_item) { +      if (proxy_flag && wrapping_member_flag) +	Printv(proxy_class_constants_code, constants_code, NIL); +      else +	Printv(module_class_constants_code, constants_code, NIL); +    } +    // Cleanup +    Swig_restore(n); +    Delete(new_value); +    Delete(return_type); +    Delete(constants_code); +    return SWIG_OK; +  } + +  /* ----------------------------------------------------------------------------- +   * insertDirective() +   * ----------------------------------------------------------------------------- */ + +  virtual int insertDirective(Node *n) { +    int ret = SWIG_OK; +    String *code = Getattr(n, "code"); +    String *section = Getattr(n, "section"); +    Replaceall(code, "$module", module_class_name); +    Replaceall(code, "$imclassname", imclass_name); +    Replaceall(code, "$dllimport", dllimport); + +    if (!ImportMode && (Cmp(section, "proxycode") == 0)) { +      if (proxy_class_code) { +	Swig_typemap_replace_embedded_typemap(code, n); +	int offset = Len(code) > 0 && *Char(code) == '\n' ? 1 : 0; +	Printv(proxy_class_code, Char(code) + offset, "\n", NIL); +      } +    } else { +      ret = Language::insertDirective(n); +    } +    return ret; +  } + +  /* ----------------------------------------------------------------------------- +   * pragmaDirective() +   * +   * Valid Pragmas: +   * imclassbase            - base (extends) for the intermediary class +   * imclassclassmodifiers  - class modifiers for the intermediary class +   * imclasscode            - text (C# code) is copied verbatim to the intermediary class +   * imclassimports         - import statements for the intermediary class +   * imclassinterfaces      - interface (implements) for the intermediary class +   * +   * modulebase              - base (extends) for the module class +   * moduleclassmodifiers    - class modifiers for the module class +   * modulecode              - text (C# code) is copied verbatim to the module class +   * moduleimports           - import statements for the module class +   * moduleinterfaces        - interface (implements) for the module class +   * +   * ----------------------------------------------------------------------------- */ + +  virtual int pragmaDirective(Node *n) { +    if (!ImportMode) { +      String *lang = Getattr(n, "lang"); +      String *code = Getattr(n, "name"); +      String *value = Getattr(n, "value"); + +      if (Strcmp(lang, "csharp") == 0) { + +	String *strvalue = NewString(value); +	Replaceall(strvalue, "\\\"", "\""); + +	if (Strcmp(code, "imclassbase") == 0) { +	  Delete(imclass_baseclass); +	  imclass_baseclass = Copy(strvalue); +	} else if (Strcmp(code, "imclassclassmodifiers") == 0) { +	  Delete(imclass_class_modifiers); +	  imclass_class_modifiers = Copy(strvalue); +	} else if (Strcmp(code, "imclasscode") == 0) { +	  Printf(imclass_class_code, "%s\n", strvalue); +	} else if (Strcmp(code, "imclassimports") == 0) { +	  Delete(imclass_imports); +	  imclass_imports = Copy(strvalue); +	} else if (Strcmp(code, "imclassinterfaces") == 0) { +	  Delete(imclass_interfaces); +	  imclass_interfaces = Copy(strvalue); +	} else if (Strcmp(code, "modulebase") == 0) { +	  Delete(module_baseclass); +	  module_baseclass = Copy(strvalue); +	} else if (Strcmp(code, "moduleclassmodifiers") == 0) { +	  Delete(module_class_modifiers); +	  module_class_modifiers = Copy(strvalue); +	} else if (Strcmp(code, "modulecode") == 0) { +	  Printf(module_class_code, "%s\n", strvalue); +	} else if (Strcmp(code, "moduleimports") == 0) { +	  Delete(module_imports); +	  module_imports = Copy(strvalue); +	} else if (Strcmp(code, "moduleinterfaces") == 0) { +	  Delete(module_interfaces); +	  module_interfaces = Copy(strvalue); +	} else { +	  Swig_error(input_file, line_number, "Unrecognized pragma.\n"); +	} +	Delete(strvalue); +      } +    } +    return Language::pragmaDirective(n); +  } + +  /* ----------------------------------------------------------------------------- +   * getQualifiedInterfaceName() +   * ----------------------------------------------------------------------------- */ + +  String *getQualifiedInterfaceName(Node *n) { +    String *ret = Getattr(n, "interface:qname"); +    if (!ret) { +      String *nspace = Getattr(n, "sym:nspace"); +      String *interface_name = Getattr(n, "interface:name"); +      if (nspace) { +	if (namespce) +	  ret = NewStringf("%s.%s.%s", namespce, nspace, interface_name); +	else +	  ret = NewStringf("%s.%s", nspace, interface_name); +      } else { +	ret = Copy(interface_name); +      } +      Setattr(n, "interface:qname", ret); +    } +    return ret; +  } + +  /* ----------------------------------------------------------------------------- +   * getInterfaceName() +   * ----------------------------------------------------------------------------- */ + +  String *getInterfaceName(SwigType *t, bool qualified) { +    String *interface_name = NULL; +    if (proxy_flag) { +      Node *n = classLookup(t); +      if (n && Getattr(n, "interface:name")) +	interface_name = qualified ? getQualifiedInterfaceName(n) : Getattr(n, "interface:name"); +    } +    return interface_name; +  } + +  /* ----------------------------------------------------------------------------- +   * addInterfaceNameAndUpcasts() +   * ----------------------------------------------------------------------------- */ + +  void addInterfaceNameAndUpcasts(SwigType *smart, String *interface_list, String *interface_upcasts, List *base_list, SwigType *c_classname) { +    for (Iterator it = First(base_list); it.item; it = Next(it)) { +      Node *base = it.item; +      SwigType *c_baseclassname = Getattr(base, "name"); +      String *interface_name = Getattr(base, "interface:name"); +      if (Len(interface_list)) +	Append(interface_list, ", "); +      Append(interface_list, interface_name); + +      Node *attributes = NewHash(); +      String *interface_code = Copy(typemapLookup(base, "csinterfacecode", Getattr(base, "classtypeobj"), WARN_CSHARP_TYPEMAP_INTERFACECODE_UNDEF, attributes)); +      String *cptr_method_name = 0; +      if (interface_code) { +        Replaceall(interface_code, "$interfacename", interface_name); +	Printv(interface_upcasts, interface_code, NIL); +	cptr_method_name = Copy(Getattr(attributes, "tmap:csinterfacecode:cptrmethod")); +      } +      if (!cptr_method_name) +	cptr_method_name = NewStringf("%s_GetInterfaceCPtr", interface_name); +      Replaceall(cptr_method_name, ".", "_"); +      Replaceall(cptr_method_name, "$interfacename", interface_name); + +      String *upcast_method_name = Swig_name_member(getNSpace(), getClassPrefix(), cptr_method_name); +      upcastsCode(smart, upcast_method_name, c_classname, c_baseclassname); + +      Delete(upcast_method_name); +      Delete(cptr_method_name); +      Delete(interface_code); +    } +  } + +  /* ----------------------------------------------------------------------------- +   * upcastsCode() +   * +   * Add code for C++ casting to base class +   * ----------------------------------------------------------------------------- */ + +  void upcastsCode(SwigType *smart, String *upcast_method_name, SwigType *c_classname, SwigType *c_baseclassname) { +    String *wname = Swig_name_wrapper(upcast_method_name); + +    Printv(imclass_cppcasts_code, "\n  [global::System.Runtime.InteropServices.DllImport(\"", dllimport, "\", EntryPoint=\"", wname, "\")]\n", NIL); +    Printf(imclass_cppcasts_code, "  public static extern global::System.IntPtr %s(global::System.IntPtr jarg1);\n", upcast_method_name); + +    Replaceall(imclass_cppcasts_code, "$csclassname", proxy_class_name); + +    String *classname = SwigType_namestr(c_classname); +    String *baseclassname = SwigType_namestr(c_baseclassname); +    if (smart) { +      String *smartnamestr = SwigType_namestr(smart); +      String *bsmartnamestr = SwigType_namestr(smart); + +      // TODO: SwigType_typedef_resolve_all on a String instead of SwigType is incorrect for templates +      SwigType *rclassname = SwigType_typedef_resolve_all(classname); +      SwigType *rbaseclassname = SwigType_typedef_resolve_all(baseclassname); +      Replaceall(bsmartnamestr, rclassname, rbaseclassname); + +      Printv(upcasts_code, +	  "SWIGEXPORT ", bsmartnamestr, " * SWIGSTDCALL ", wname, "(", smartnamestr, " *jarg1) {\n", +	  "    return jarg1 ? new ", bsmartnamestr, "(*jarg1) : 0;\n" +	  "}\n", "\n", NIL); + +      Delete(rbaseclassname); +      Delete(rclassname); +      Delete(bsmartnamestr); +      Delete(smartnamestr); +    } else { +      Printv(upcasts_code, +	  "SWIGEXPORT ", baseclassname, " * SWIGSTDCALL ", wname, "(", classname, " *jarg1) {\n", +	  "    return (", baseclassname, " *)jarg1;\n" +	  "}\n", "\n", NIL); +    } + +    Delete(baseclassname); +    Delete(classname); +    Delete(wname); +  } + +  /* ----------------------------------------------------------------------------- +   * emitProxyClassDefAndCPPCasts() +   * ----------------------------------------------------------------------------- */ + +  void emitProxyClassDefAndCPPCasts(Node *n) { +    SwigType *c_classname = Getattr(n, "name"); +    SwigType *c_baseclassname = NULL; +    String *baseclass = NULL; +    String *interface_list = NewStringEmpty(); +    String *interface_upcasts = NewStringEmpty(); +    SwigType *typemap_lookup_type = Getattr(n, "classtypeobj"); +    bool feature_director = Swig_directorclass(n) ? true : false; +    bool has_outerclass = Getattr(n, "nested:outer") != 0 && !GetFlag(n, "feature:flatnested"); +    SwigType *smart = Swig_cparse_smartptr(n); + +    // Inheritance from pure C# classes +    Node *attributes = NewHash(); +    const String *pure_baseclass = typemapLookup(n, "csbase", typemap_lookup_type, WARN_NONE, attributes); +    bool purebase_replace = GetFlag(attributes, "tmap:csbase:replace") ? true : false; +    bool purebase_notderived = GetFlag(attributes, "tmap:csbase:notderived") ? true : false; +    Delete(attributes); + +    // C++ inheritance +    if (!purebase_replace) { +      List *baselist = Getattr(n, "bases"); +      if (baselist) { +	Iterator base = First(baselist); +	while (base.item) { +	  if (!(GetFlag(base.item, "feature:ignore") || GetFlag(base.item, "feature:interface"))) { +	    SwigType *baseclassname = Getattr(base.item, "name"); +	    if (!c_baseclassname) { +	      String *name = getProxyName(baseclassname); +	      if (name) { +		c_baseclassname = baseclassname; +		baseclass = name; +	      } +	    } else { +	      /* Warn about multiple inheritance for additional base class(es) */ +	      String *proxyclassname = Getattr(n, "classtypeobj"); +	      Swig_warning(WARN_CSHARP_MULTIPLE_INHERITANCE, Getfile(n), Getline(n), +		  "Warning for %s, base %s ignored. Multiple inheritance is not supported in C#.\n", SwigType_namestr(proxyclassname), SwigType_namestr(baseclassname)); +	    } +	  } +	  base = Next(base); +	} +      } +    } +    List *interface_bases = Getattr(n, "interface:bases"); +    if (interface_bases) +      addInterfaceNameAndUpcasts(smart, interface_list, interface_upcasts, interface_bases, c_classname); + +    bool derived = baseclass != 0; +    if (derived && purebase_notderived) +      pure_baseclass = empty_string; +    const String *wanted_base = baseclass ? baseclass : pure_baseclass; + +    if (purebase_replace) { +      wanted_base = pure_baseclass; +      derived = false; +      baseclass = NULL; +      if (purebase_notderived) +        Swig_error(Getfile(n), Getline(n), "The csbase typemap for proxy %s must contain just one of the 'replace' or 'notderived' attributes.\n", typemap_lookup_type); +    } else if (Len(pure_baseclass) > 0 && Len(baseclass) > 0) { +      Swig_warning(WARN_CSHARP_MULTIPLE_INHERITANCE, Getfile(n), Getline(n), +		   "Warning for %s, base %s ignored. Multiple inheritance is not supported in C#. " +		   "Perhaps you need one of the 'replace' or 'notderived' attributes in the csbase typemap?\n", typemap_lookup_type, pure_baseclass); +    } + +    // Pure C# interfaces +    const String *pure_interfaces = typemapLookup(n, derived ? "csinterfaces_derived" : "csinterfaces", typemap_lookup_type, WARN_NONE); +    if (*Char(interface_list) && *Char(pure_interfaces)) +      Append(interface_list, ", "); +    Append(interface_list, pure_interfaces); +    // Start writing the proxy class +    if (!has_outerclass) +      Printv(proxy_class_def, typemapLookup(n, "csimports", typemap_lookup_type, WARN_NONE),	// Import statements +	   "\n", NIL); + +    // Class attributes +    const String *csattributes = typemapLookup(n, "csattributes", typemap_lookup_type, WARN_NONE); +    if (csattributes && *Char(csattributes)) +      Printf(proxy_class_def, "%s\n", csattributes); + +    Printv(proxy_class_def, typemapLookup(n, "csclassmodifiers", typemap_lookup_type, WARN_CSHARP_TYPEMAP_CLASSMOD_UNDEF),	// Class modifiers +	   " $csclassname",	// Class name and base class +	   (*Char(wanted_base) || *Char(interface_list)) ? " : " : "", wanted_base, (*Char(wanted_base) && *Char(interface_list)) ?	// Interfaces +	   ", " : "", interface_list, " {", derived ? typemapLookup(n, "csbody_derived", typemap_lookup_type, WARN_CSHARP_TYPEMAP_CSBODY_UNDEF) :	// main body of class +	   typemapLookup(n, "csbody", typemap_lookup_type, WARN_CSHARP_TYPEMAP_CSBODY_UNDEF),	// main body of class +	   NIL); + +    // C++ destructor is wrapped by the Finalize and Dispose methods + +    const char *tmap_method = derived ? "csdestruct_derived" : "csdestruct"; +    const String *tm = typemapExists(n, tmap_method, typemap_lookup_type); +    if (tm) { +      Swig_error(Getfile(tm), Getline(tm), +	  "A deprecated %s typemap was found for %s, please remove it and replace all csdestruct, csdestruct_derived and csfinalize typemaps by the csdispose, csdispose_derived, csdisposing and csdisposing_derived typemaps.\n", +	  tmap_method, proxy_class_name); +    } +    tmap_method = "csfinalize"; +    tm = typemapExists(n, tmap_method, typemap_lookup_type); +    if (tm) { +      Swig_error(Getfile(tm), Getline(tm), +	  "A deprecated %s typemap was found for %s, please remove it and replace all csdestruct, csdestruct_derived and csfinalize typemaps by the csdispose, csdispose_derived, csdisposing and csdisposing_derived typemaps.\n", +	  tmap_method, proxy_class_name); +    } + +    tmap_method = derived ? "csdisposing_derived" : "csdisposing"; +    String *destruct = NewString(""); +    attributes = NewHash(); +    const String *destruct_methodname = NULL; +    const String *destruct_methodmodifiers = NULL; +    const String *destruct_parameters = NULL; +    if (derived) { +      tm = typemapLookup(n, "csdisposing_derived", typemap_lookup_type, WARN_NONE, attributes); +      destruct_methodname = Getattr(attributes, "tmap:csdisposing_derived:methodname"); +      destruct_methodmodifiers = Getattr(attributes, "tmap:csdisposing_derived:methodmodifiers"); +      destruct_parameters = Getattr(attributes, "tmap:csdisposing_derived:parameters"); +    } else { +      tm = typemapLookup(n, "csdisposing", typemap_lookup_type, WARN_NONE, attributes); +      destruct_methodname = Getattr(attributes, "tmap:csdisposing:methodname"); +      destruct_methodmodifiers = Getattr(attributes, "tmap:csdisposing:methodmodifiers"); +      destruct_parameters = Getattr(attributes, "tmap:csdisposing:parameters"); +    } +    if (tm && *Char(tm)) { +      if (!destruct_methodname) { +	Swig_error(Getfile(n), Getline(n), "No methodname attribute defined in %s typemap for %s\n", tmap_method, proxy_class_name); +      } +      if (!destruct_methodmodifiers) { +	Swig_error(Getfile(n), Getline(n), +		   "No methodmodifiers attribute defined in %s typemap for %s.\n", tmap_method, proxy_class_name); +      } +      if (!destruct_parameters) +	destruct_parameters = empty_string; +    } +    // Emit the Finalize and Dispose methods +    if (tm) { +      // Finalize and Dispose methods +      Printv(proxy_class_def, typemapLookup(n, derived ? "csdispose_derived" : "csdispose", typemap_lookup_type, WARN_NONE), NIL); +      // Dispose(bool disposing) method +      Printv(destruct, tm, NIL); +      if (*Char(destructor_call)) +	Replaceall(destruct, "$imcall", destructor_call); +      else +	Replaceall(destruct, "$imcall", "throw new global::System.MethodAccessException(\"C++ destructor does not have public access\")"); +      if (*Char(destruct)) { +	Printv(proxy_class_def, "\n  ", NIL); +	const String *methodmods = Getattr(n, "destructmethodmodifiers"); +	if (methodmods) +	  Printv(proxy_class_def, methodmods, NIL); +	else +	  Printv(proxy_class_def, destruct_methodmodifiers, " ", derived ? "override" : "virtual", NIL); +	Printv(proxy_class_def, " void ", destruct_methodname, "(", destruct_parameters, ") ", destruct, "\n", NIL); +      } +    } +    if (*Char(interface_upcasts)) +      Printv(proxy_class_def, interface_upcasts, NIL); + +    if (feature_director) { +      // Generate director connect method +      // put this in classDirectorEnd ??? +      Printf(proxy_class_code, "  private void SwigDirectorConnect() {\n"); + +      int i; +      for (i = first_class_dmethod; i < curr_class_dmethod; ++i) { +	UpcallData *udata = Getitem(dmethods_seq, i); +	String *method = Getattr(udata, "method"); +	String *methid = Getattr(udata, "class_methodidx"); +	String *overname = Getattr(udata, "overname"); +	Printf(proxy_class_code, "    if (SwigDerivedClassHasMethod(\"%s\", swigMethodTypes%s))\n", method, methid); +	Printf(proxy_class_code, "      swigDelegate%s = new SwigDelegate%s_%s(SwigDirectorMethod%s);\n", methid, proxy_class_name, methid, overname); +      } +      String *director_connect_method_name = Swig_name_member(getNSpace(), getClassPrefix(), "director_connect"); +      Printf(proxy_class_code, "    %s.%s(swigCPtr", imclass_name, director_connect_method_name); +      for (i = first_class_dmethod; i < curr_class_dmethod; ++i) { +	UpcallData *udata = Getitem(dmethods_seq, i); +	String *methid = Getattr(udata, "class_methodidx"); +	Printf(proxy_class_code, ", swigDelegate%s", methid); +      } +      Printf(proxy_class_code, ");\n"); +      Printf(proxy_class_code, "  }\n"); + +      if (first_class_dmethod < curr_class_dmethod) { +	// Only emit if there is at least one director method +	Printf(proxy_class_code, "\n"); +	Printf(proxy_class_code, "  private bool SwigDerivedClassHasMethod(string methodName, global::System.Type[] methodTypes) {\n"); +	Printf(proxy_class_code, "    global::System.Reflection.MethodInfo[] methodInfos = this.GetType().GetMethods(\n"); +	Printf(proxy_class_code, "        global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance);\n"); +	Printf(proxy_class_code, "    foreach (global::System.Reflection.MethodInfo methodInfo in methodInfos) {\n"); +	Printf(proxy_class_code, "      if (methodInfo.DeclaringType == null)\n"); +	Printf(proxy_class_code, "        continue;\n\n"); +	Printf(proxy_class_code, "      if (methodInfo.Name != methodName)\n"); +	Printf(proxy_class_code, "        continue;\n\n"); +	Printf(proxy_class_code, "      var parameters = methodInfo.GetParameters();\n"); +	Printf(proxy_class_code, "      if (parameters.Length != methodTypes.Length)\n"); +	Printf(proxy_class_code, "        continue;\n\n"); +	Printf(proxy_class_code, "      bool parametersMatch = true;\n"); +	Printf(proxy_class_code, "      for (var i = 0; i < parameters.Length; i++) {\n"); +	Printf(proxy_class_code, "        if (parameters[i].ParameterType != methodTypes[i]) {\n"); +	Printf(proxy_class_code, "          parametersMatch = false;\n"); +	Printf(proxy_class_code, "          break;\n"); +	Printf(proxy_class_code, "        }\n"); +	Printf(proxy_class_code, "      }\n\n"); +	Printf(proxy_class_code, "      if (!parametersMatch)\n"); +	Printf(proxy_class_code, "        continue;\n\n"); +	Printf(proxy_class_code, "      if (methodInfo.IsVirtual && (methodInfo.DeclaringType.IsSubclassOf(typeof(%s))) &&\n", proxy_class_name); +	Printf(proxy_class_code, "        methodInfo.DeclaringType != methodInfo.GetBaseDefinition().DeclaringType) {\n"); +	Printf(proxy_class_code, "        return true;\n"); +	Printf(proxy_class_code, "      }\n"); +	Printf(proxy_class_code, "    }\n\n"); +  Printf(proxy_class_code, "    return false;\n"); + +	/* Could add this code to cover corner case where the GetMethod() returns a method which allows type +	 * promotion, eg it will return foo(double), if looking for foo(int). +	 if (hasDerivedMethod) { +	 hasDerivedMethod = false; +	 if (methodInfo != null) +	 { +	 hasDerivedMethod = true; +	 ParameterInfo[] parameterArray1 = methodInfo.GetParameters(); +	 for (int i=0; i<methodTypes.Length; i++) +	 { +	 if (parameterArray1[0].ParameterType != methodTypes[0]) +	 { +	 hasDerivedMethod = false; +	 break; +	 } +	 } +	 } +	 } +	 */ +	//Printf(proxy_class_code, "    return hasDerivedMethod;\n"); +	Printf(proxy_class_code, "  }\n"); +      } + +      if (Len(director_delegate_callback) > 0) +	Printv(proxy_class_code, director_delegate_callback, NIL); +      if (Len(director_delegate_definitions) > 0) +	Printv(proxy_class_code, "\n", director_delegate_definitions, NIL); +      if (Len(director_delegate_instances) > 0) +	Printv(proxy_class_code, "\n", director_delegate_instances, NIL); +      if (Len(director_method_types) > 0) +	Printv(proxy_class_code, "\n", director_method_types, NIL); + +      Delete(director_callback_typedefs); +      director_callback_typedefs = NULL; +      Delete(director_callbacks); +      director_callbacks = NULL; +      Delete(director_delegate_callback); +      director_delegate_callback = NULL; +      Delete(director_delegate_definitions); +      director_delegate_definitions = NULL; +      Delete(director_delegate_instances); +      director_delegate_instances = NULL; +      Delete(director_method_types); +      director_method_types = NULL; +      Delete(director_connect_parms); +      director_connect_parms = NULL; +      Delete(director_connect_method_name); +    } + +    Delete(interface_upcasts); +    Delete(interface_list); +    Delete(attributes); +    Delete(destruct); + +    // Emit extra user code +    Printv(proxy_class_def, typemapLookup(n, "cscode", typemap_lookup_type, WARN_NONE),	// extra C# code +	   "\n", NIL); + +    if (derived) { +      String *upcast_method_name = Swig_name_member(getNSpace(), getClassPrefix(), smart != 0 ? "SWIGSmartPtrUpcast" : "SWIGUpcast"); +      upcastsCode(smart, upcast_method_name, c_classname, c_baseclassname); +      Delete(upcast_method_name); +    } + +    Delete(smart); +  } + +  /* ---------------------------------------------------------------------- +   * emitInterfaceDeclaration() +   * ---------------------------------------------------------------------- */ + +  void emitInterfaceDeclaration(Node *n, String *interface_name, File *f_interface) { +    Printv(f_interface, typemapLookup(n, "csimports", Getattr(n, "classtypeobj"), WARN_NONE), "\n", NIL); +    Printv(f_interface, typemapLookup(n, "csinterfacemodifiers", Getattr(n, "classtypeobj"), WARN_CSHARP_TYPEMAP_INTERFACEMODIFIERS_UNDEF), NIL); +    Printf(f_interface, " %s", interface_name); +    if (List *baselist = Getattr(n, "bases")) { +      String *bases = 0; +      for (Iterator base = First(baselist); base.item; base = Next(base)) { +	if (GetFlag(base.item, "feature:ignore") || !GetFlag(base.item, "feature:interface")) +	  continue; // TODO: warn about skipped non-interface bases +	String *base_iname = Getattr(base.item, "interface:name"); +	if (!bases) +	  bases = NewStringf(" : %s", base_iname); +	else { +	  Append(bases, ", "); +	  Append(bases, base_iname); +	} +      } +      if (bases) { +	Printv(f_interface, bases, NIL); +	Delete(bases); +      } +    } +    Printf(f_interface, " {\n"); + +    Node *attributes = NewHash(); +    String *interface_code = Copy(typemapLookup(n, "csinterfacecode", Getattr(n, "classtypeobj"), WARN_CSHARP_TYPEMAP_INTERFACECODE_UNDEF, attributes)); +    if (interface_code) { +      String *interface_declaration = Copy(Getattr(attributes, "tmap:csinterfacecode:declaration")); +      if (interface_declaration) { +        Replaceall(interface_declaration, "$interfacename", interface_name); +	Printv(f_interface, interface_declaration, NIL); +	Delete(interface_declaration); +      } +      Delete(interface_code); +    } +  } + +  /* ---------------------------------------------------------------------- +   * classHandler() +   * ---------------------------------------------------------------------- */ + +  virtual int classHandler(Node *n) { +    String *nspace = getNSpace(); +    File *f_proxy = NULL; +    File *f_interface = NULL; +    // save class local variables +    String *old_proxy_class_name = proxy_class_name; +    String *old_full_imclass_name = full_imclass_name; +    String *old_destructor_call = destructor_call; +    String *old_proxy_class_constants_code = proxy_class_constants_code; +    String *old_proxy_class_def = proxy_class_def; +    String *old_proxy_class_code = proxy_class_code; +    bool has_outerclass = Getattr(n, "nested:outer") && !GetFlag(n, "feature:flatnested"); +    String *old_interface_class_code = interface_class_code; +    interface_class_code = 0; + +    if (proxy_flag) { +      proxy_class_name = NewString(Getattr(n, "sym:name")); +      String *interface_name = GetFlag(n, "feature:interface") ? Getattr(n, "interface:name") : 0; +      if (Node *outer = Getattr(n, "nested:outer")) { +	String *outerClassesPrefix = Copy(Getattr(outer, "sym:name")); +	for (outer = Getattr(outer, "nested:outer"); outer != 0; outer = Getattr(outer, "nested:outer")) { +	  Push(outerClassesPrefix, "."); +	  Push(outerClassesPrefix, Getattr(outer, "sym:name")); +	} +	String *fnspace = nspace ? NewStringf("%s.%s", nspace, outerClassesPrefix) : outerClassesPrefix; +	if (!addSymbol(proxy_class_name, n, fnspace)) +	  return SWIG_ERROR; +	if (interface_name && !addInterfaceSymbol(interface_name, n, fnspace)) +	  return SWIG_ERROR; +	if (nspace) +	  Delete(fnspace); +	Delete(outerClassesPrefix); +      } else { +	if (!addSymbol(proxy_class_name, n, nspace)) +	  return SWIG_ERROR; +	if (interface_name && !addInterfaceSymbol(interface_name, n, nspace)) +	  return SWIG_ERROR; +      } + +      if (!nspace) { +	full_imclass_name = NewStringf("%s", imclass_name); +	if (Cmp(proxy_class_name, imclass_name) == 0) { +	  Printf(stderr, "Class name cannot be equal to intermediary class name: %s\n", proxy_class_name); +	  Exit(EXIT_FAILURE); +	} + +	if (Cmp(proxy_class_name, module_class_name) == 0) { +	  Printf(stderr, "Class name cannot be equal to module class name: %s\n", proxy_class_name); +	  Exit(EXIT_FAILURE); +	} +      } else { +	if (namespce) { +	  full_imclass_name = NewStringf("%s.%s", namespce, imclass_name); +	} else { +	  full_imclass_name = NewStringf("%s", imclass_name); +	} +      } + +      if (!has_outerclass) { +	String *output_directory = outputDirectory(nspace); +	f_proxy = getOutputFile(output_directory, proxy_class_name); + +	addOpenNamespace(nspace, f_proxy); +        Delete(output_directory); +      } +      else +	++nesting_depth; + +      proxy_class_def = NewString(""); +      proxy_class_code = NewString(""); +      destructor_call = NewString(""); +      proxy_class_constants_code = NewString(""); + +      if (GetFlag(n, "feature:interface")) { +	interface_class_code = NewString(""); +	String *output_directory = outputDirectory(nspace); +	f_interface = getOutputFile(output_directory, interface_name); +	addOpenNamespace(nspace, f_interface); +	emitInterfaceDeclaration(n, interface_name, interface_class_code); +        Delete(output_directory); +      } +    } + +    Language::classHandler(n); + +    if (proxy_flag) { + +      emitProxyClassDefAndCPPCasts(n); + +      String *csclazzname = Swig_name_member(getNSpace(), getClassPrefix(), ""); // mangled full proxy class name + +      Replaceall(proxy_class_def, "$csclassname", proxy_class_name); +      Replaceall(proxy_class_code, "$csclassname", proxy_class_name); +      Replaceall(proxy_class_constants_code, "$csclassname", proxy_class_name); +      Replaceall(interface_class_code, "$csclassname", proxy_class_name); + +      Replaceall(proxy_class_def, "$csclazzname", csclazzname); +      Replaceall(proxy_class_code, "$csclazzname", csclazzname); +      Replaceall(proxy_class_constants_code, "$csclazzname", csclazzname); +      Replaceall(interface_class_code, "$csclazzname", csclazzname); + +      Replaceall(proxy_class_def, "$module", module_class_name); +      Replaceall(proxy_class_code, "$module", module_class_name); +      Replaceall(proxy_class_constants_code, "$module", module_class_name); +      Replaceall(interface_class_code, "$module", module_class_name); + +      Replaceall(proxy_class_def, "$imclassname", full_imclass_name); +      Replaceall(proxy_class_code, "$imclassname", full_imclass_name); +      Replaceall(proxy_class_constants_code, "$imclassname", full_imclass_name); +      Replaceall(interface_class_code, "$imclassname", full_imclass_name); + +      Replaceall(proxy_class_def, "$dllimport", dllimport); +      Replaceall(proxy_class_code, "$dllimport", dllimport); +      Replaceall(proxy_class_constants_code, "$dllimport", dllimport); +      Replaceall(interface_class_code, "$dllimport", dllimport); + +      if (!has_outerclass) +	Printv(f_proxy, proxy_class_def, proxy_class_code, NIL); +      else { +	Swig_offset_string(proxy_class_def, nesting_depth); +	Append(old_proxy_class_code, proxy_class_def); +	Swig_offset_string(proxy_class_code, nesting_depth); +	Append(old_proxy_class_code, proxy_class_code); +      } + +      // Write out all the constants +      if (Len(proxy_class_constants_code) != 0) { +	if (!has_outerclass) +	  Printv(f_proxy, proxy_class_constants_code, NIL); +	else { +	  Swig_offset_string(proxy_class_constants_code, nesting_depth); +	  Append(old_proxy_class_code, proxy_class_constants_code); +	} +      } +      if (!has_outerclass) { +	Printf(f_proxy, "}\n"); +	addCloseNamespace(nspace, f_proxy); +	if (f_proxy != f_single_out) +	  Delete(f_proxy); +	f_proxy = NULL; +      } else { +	for (int i = 0; i < nesting_depth; ++i) +	  Append(old_proxy_class_code, "  "); +	Append(old_proxy_class_code, "}\n\n"); +	--nesting_depth; +      } + +      if (f_interface) { +	Printv(f_interface, interface_class_code, "}\n", NIL); +	addCloseNamespace(nspace, f_interface); +	if (f_interface != f_single_out) +	  Delete(f_interface); +	f_interface = 0; +      } + +      emitDirectorExtraMethods(n); + +      Delete(interface_class_code); +      interface_class_code = old_interface_class_code; +      Delete(csclazzname); +      Delete(proxy_class_name); +      proxy_class_name = old_proxy_class_name; +      Delete(full_imclass_name); +      full_imclass_name = old_full_imclass_name; +      Delete(destructor_call); +      destructor_call = old_destructor_call; +      Delete(proxy_class_constants_code); +      proxy_class_constants_code = old_proxy_class_constants_code; +      Delete(proxy_class_def); +      proxy_class_def = old_proxy_class_def; +      Delete(proxy_class_code); +      proxy_class_code = old_proxy_class_code; +    } +    return SWIG_OK; +  } + +  /* ---------------------------------------------------------------------- +   * memberfunctionHandler() +   * ---------------------------------------------------------------------- */ + +  virtual int memberfunctionHandler(Node *n) { +    Language::memberfunctionHandler(n); + +    if (proxy_flag) { +      String *overloaded_name = getOverloadedName(n); +      String *intermediary_function_name = Swig_name_member(getNSpace(), getClassPrefix(), overloaded_name); +      Setattr(n, "proxyfuncname", Getattr(n, "sym:name")); +      Setattr(n, "imfuncname", intermediary_function_name); +      proxyClassFunctionHandler(n); +      Delete(overloaded_name); +    } +    return SWIG_OK; +  } + +  /* ---------------------------------------------------------------------- +   * staticmemberfunctionHandler() +   * ---------------------------------------------------------------------- */ + +  virtual int staticmemberfunctionHandler(Node *n) { + +    static_flag = true; +    Language::staticmemberfunctionHandler(n); + +    if (proxy_flag) { +      String *overloaded_name = getOverloadedName(n); +      String *intermediary_function_name = Swig_name_member(getNSpace(), getClassPrefix(), overloaded_name); +      Setattr(n, "proxyfuncname", Getattr(n, "sym:name")); +      Setattr(n, "imfuncname", intermediary_function_name); +      proxyClassFunctionHandler(n); +      Delete(overloaded_name); +    } +    static_flag = false; + +    return SWIG_OK; +  } + + +  /* ----------------------------------------------------------------------------- +   * proxyClassFunctionHandler() +   * +   * Function called for creating a C# wrapper function around a c++ function in the  +   * proxy class. Used for both static and non-static C++ class functions. +   * C++ class static functions map to C# static functions. +   * Two extra attributes in the Node must be available. These are "proxyfuncname" -  +   * the name of the C# class proxy function, which in turn will call "imfuncname" -  +   * the intermediary (PInvoke) function name in the intermediary class. +   * ----------------------------------------------------------------------------- */ + +  void proxyClassFunctionHandler(Node *n) { +    SwigType *t = Getattr(n, "type"); +    ParmList *l = Getattr(n, "parms"); +    String *intermediary_function_name = Getattr(n, "imfuncname"); +    String *proxy_function_name = Getattr(n, "proxyfuncname"); +    String *tm; +    Parm *p; +    Parm *last_parm = 0; +    int i; +    String *imcall = NewString(""); +    String *return_type = NewString(""); +    String *function_code = NewString(""); +    bool setter_flag = false; +    String *pre_code = NewString(""); +    String *post_code = NewString(""); +    String *terminator_code = NewString(""); +    bool is_interface = GetFlag(parentNode(n), "feature:interface") && !checkAttribute(n, "kind", "variable") +      && !static_flag && Getattr(n, "interface:owner") == 0; + +    if (!proxy_flag) +      return; + +    // Wrappers not wanted for some methods where the parameters cannot be overloaded in C# +    if (Getattr(n, "overload:ignore")) +      return; + +    // Don't generate proxy method for additional explicitcall method used in directors +    if (GetFlag(n, "explicitcall")) +      return; + +    if (l) { +      if (SwigType_type(Getattr(l, "type")) == T_VOID) { +	l = nextSibling(l); +      } +    } + +    /* Attach the non-standard typemaps to the parameter list */ +    Swig_typemap_attach_parms("in", l, NULL); +    Swig_typemap_attach_parms("cstype", l, NULL); +    Swig_typemap_attach_parms("csin", l, NULL); + +    /* Get return types */ +    if ((tm = Swig_typemap_lookup("cstype", n, "", 0))) { +      // Note that in the case of polymorphic (covariant) return types, the method's return type is changed to be the base of the C++ return type +      SwigType *covariant = Getattr(n, "covariant"); +      String *cstypeout = Getattr(n, "tmap:cstype:out");	// the type in the cstype typemap's out attribute overrides the type in the typemap +      if (cstypeout) +	tm = cstypeout; +      substituteClassname(covariant ? covariant : t, tm); +      Printf(return_type, "%s", tm); +      if (covariant) +	Swig_warning(WARN_CSHARP_COVARIANT_RET, input_file, line_number, +		     "Covariant return types not supported in C#. Proxy method will return %s.\n", SwigType_str(covariant, 0)); +    } else { +      Swig_warning(WARN_CSHARP_TYPEMAP_CSWTYPE_UNDEF, input_file, line_number, "No cstype typemap defined for %s\n", SwigType_str(t, 0)); +    } + +    if (wrapping_member_flag && !enum_constant_flag) { +      // Properties +      setter_flag = (Cmp(Getattr(n, "sym:name"), Swig_name_set(getNSpace(), Swig_name_member(0, getClassPrefix(), variable_name))) == 0); +      if (setter_flag) +        Swig_typemap_attach_parms("csvarin", l, NULL); +    } + +    /* Start generating the proxy function */ +    const String *outattributes = Getattr(n, "tmap:cstype:outattributes"); +    if (outattributes) +      Printf(function_code, "  %s\n", outattributes); +    const String *csattributes = Getattr(n, "feature:cs:attributes"); +    if (csattributes) +      Printf(function_code, "  %s\n", csattributes); +    const String *methodmods = Getattr(n, "feature:cs:methodmodifiers"); +    if (methodmods) { +      if (is_smart_pointer()) { +	// Smart pointer classes do not mirror the inheritance hierarchy of the underlying pointer type, so no virtual/override/new required. +	String *mmods = Copy(methodmods); +	Replaceall(mmods, "override", ""); +	Replaceall(mmods, "virtual", ""); +	Replaceall(mmods, "new", ""); +	Chop(mmods);		// remove trailing whitespace +	Printf(function_code, "  %s ", mmods); +	Delete(mmods); +      } else { +	Printf(function_code, "  %s ", methodmods); +      } +    } else { +      methodmods = (is_public(n) ? public_string : protected_string); +      Printf(function_code, "  %s ", methodmods); +      if (!is_smart_pointer()) { +	// Smart pointer classes do not mirror the inheritance hierarchy of the underlying pointer type, so no virtual/override/new required. +	if (Getattr(n, "override")) +	    Printf(function_code, "override "); +	else if (checkAttribute(n, "storage", "virtual")) +	  Printf(function_code, "virtual "); +	if (Getattr(n, "hides")) +	  Printf(function_code, "new "); +      } +    } +    if (static_flag) +      Printf(function_code, "static "); +    Printf(function_code, "%s %s(", return_type, proxy_function_name); +    if (is_interface) +      Printf(interface_class_code, "  %s %s(", return_type, proxy_function_name); +     + +    Printv(imcall, full_imclass_name, ".$imfuncname(", NIL); +    if (!static_flag) +      Printf(imcall, "swigCPtr"); + +    emit_mark_varargs(l); + +    int gencomma = !static_flag; + +    /* Output each parameter */ +    for (i = 0, p = l; p; i++) { + +      /* Ignored varargs */ +      if (checkAttribute(p, "varargs:ignore", "1")) { +	p = nextSibling(p); +	continue; +      } + +      /* Ignored parameters */ +      if (checkAttribute(p, "tmap:in:numinputs", "0")) { +	p = Getattr(p, "tmap:in:next"); +	continue; +      } + +      /* Ignore the 'this' argument for variable wrappers */ +      if (!(variable_wrapper_flag && i == 0)) { +	SwigType *pt = Getattr(p, "type"); +	String *param_type = NewString(""); +        if (setter_flag) +          last_parm = p; + +	/* Get the C# parameter type */ +	if ((tm = Getattr(p, "tmap:cstype"))) { +	  substituteClassname(pt, tm); +	  const String *inattributes = Getattr(p, "tmap:cstype:inattributes"); +	  Printf(param_type, "%s%s", inattributes ? inattributes : empty_string, tm); +	} else { +	  Swig_warning(WARN_CSHARP_TYPEMAP_CSWTYPE_UNDEF, input_file, line_number, "No cstype typemap defined for %s\n", SwigType_str(pt, 0)); +	} + +	if (gencomma) +	  Printf(imcall, ", "); + +	String *arg = makeParameterName(n, p, i, setter_flag); + +	// Use typemaps to transform type used in C# wrapper function (in proxy class) to type used in PInvoke function (in intermediary class) +	if ((tm = Getattr(p, "tmap:csin"))) { +	  substituteClassname(pt, tm); +	  Replaceall(tm, "$csinput", arg); +          String *pre = Getattr(p, "tmap:csin:pre"); +          if (pre) { +            substituteClassname(pt, pre); +            Replaceall(pre, "$csinput", arg); +            if (Len(pre_code) > 0) +              Printf(pre_code, "\n"); +            Printv(pre_code, pre, NIL); +          } +          String *post = Getattr(p, "tmap:csin:post"); +          if (post) { +            substituteClassname(pt, post); +            Replaceall(post, "$csinput", arg); +            if (Len(post_code) > 0) +              Printf(post_code, "\n"); +            Printv(post_code, post, NIL); +          } +          String *terminator = Getattr(p, "tmap:csin:terminator"); +          if (terminator) { +            substituteClassname(pt, terminator); +            Replaceall(terminator, "$csinput", arg); +            if (Len(terminator_code) > 0) +              Insert(terminator_code, 0, "\n"); +            Insert(terminator_code, 0, terminator); +          } +	  Printv(imcall, tm, NIL); +	} else { +	  Swig_warning(WARN_CSHARP_TYPEMAP_CSIN_UNDEF, input_file, line_number, "No csin typemap defined for %s\n", SwigType_str(pt, 0)); +	} + +	/* Add parameter to proxy function */ +	if (gencomma >= 2) { +	  Printf(function_code, ", "); +	  if (is_interface) +	    Printf(interface_class_code, ", "); +	} +	gencomma = 2; +	Printf(function_code, "%s %s", param_type, arg); +	if (is_interface) +	  Printf(interface_class_code, "%s %s", param_type, arg); + +	Delete(arg); +	Delete(param_type); +      } +      p = Getattr(p, "tmap:in:next"); +    } + +    Printf(imcall, ")"); +    Printf(function_code, ")"); +    if (is_interface) +      Printf(interface_class_code, ");\n"); + +    // Transform return type used in PInvoke function (in intermediary class) to type used in C# wrapper function (in proxy class) +    if ((tm = Swig_typemap_lookup("csout", n, "", 0))) { +      excodeSubstitute(n, tm, "csout", n); +      bool is_pre_code = Len(pre_code) > 0; +      bool is_post_code = Len(post_code) > 0; +      bool is_terminator_code = Len(terminator_code) > 0; +      if (is_pre_code || is_post_code || is_terminator_code) { +        Replaceall(tm, "\n ", "\n   "); // add extra indentation to code in typemap +        if (is_post_code) { +          Insert(tm, 0, "\n    try "); +          Printv(tm, " finally {\n", post_code, "\n    }", NIL); +        } else { +          Insert(tm, 0, "\n    "); +        } +        if (is_pre_code) { +          Insert(tm, 0, pre_code); +          Insert(tm, 0, "\n"); +        } +        if (is_terminator_code) { +          Printv(tm, "\n", terminator_code, NIL); +        } +	Insert(tm, 0, "{"); +	Printf(tm, "\n  }"); +      } +      if (GetFlag(n, "feature:new")) +	Replaceall(tm, "$owner", "true"); +      else +	Replaceall(tm, "$owner", "false"); +      substituteClassname(t, tm); + +      // For director methods: generate code to selectively make a normal polymorphic call or  +      // an explicit method call - needed to prevent infinite recursion calls in director methods. +      Node *explicit_n = Getattr(n, "explicitcallnode"); +      if (explicit_n) { +	String *ex_overloaded_name = getOverloadedName(explicit_n); +	String *ex_intermediary_function_name = Swig_name_member(getNSpace(), getClassPrefix(), ex_overloaded_name); + +	String *ex_imcall = Copy(imcall); +	Replaceall(ex_imcall, "$imfuncname", ex_intermediary_function_name); +	Replaceall(imcall, "$imfuncname", intermediary_function_name); +	String *excode = NewString(""); +	Node *directorNode = Getattr(n, "directorNode"); +	UpcallData *udata = directorNode ? Getattr(directorNode, "upcalldata") : 0; +	if (udata) { +	  String *methid = Getattr(udata, "class_methodidx"); + +	  if (!Cmp(return_type, "void")) +	    Printf(excode, "if (SwigDerivedClassHasMethod(\"%s\", swigMethodTypes%s)) %s; else %s", proxy_function_name, methid, ex_imcall, imcall); +	  else +	    Printf(excode, "(SwigDerivedClassHasMethod(\"%s\", swigMethodTypes%s) ? %s : %s)", proxy_function_name, methid, ex_imcall, imcall); + +	  Clear(imcall); +	  Printv(imcall, excode, NIL); +	} else { +	  // probably an ignored method or nodirector +	} +	Delete(excode); +	Delete(ex_overloaded_name); +      } else { +	Replaceall(imcall, "$imfuncname", intermediary_function_name); +      } +      Replaceall(tm, "$imfuncname", intermediary_function_name); +      Replaceall(tm, "$imcall", imcall); +    } else { +      Swig_warning(WARN_CSHARP_TYPEMAP_CSOUT_UNDEF, input_file, line_number, "No csout typemap defined for %s\n", SwigType_str(t, 0)); +    } + +    if (wrapping_member_flag && !enum_constant_flag) { +      // Properties +      if (generate_property_declaration_flag) {	// Ensure the declaration is generated just once should the property contain both a set and get +	// Get the C# variable type - obtained differently depending on whether a setter is required. +	String *variable_type = return_type; +	if (setter_flag) { +	  assert(last_parm);	// (last parameter is the only parameter for properties) +	  /* Get variable type - ensure the variable name is fully resolved during typemap lookup via the symbol table set in NewParmNode */ +	  SwigType *cvariable_type = Getattr(last_parm, "type"); +	  Parm *variable_parm = NewParmNode(cvariable_type, n); +	  if ((tm = Swig_typemap_lookup("cstype", variable_parm, "", 0))) { +	    String *cstypeout = Getattr(variable_parm, "tmap:cstype:out");	// the type in the cstype typemap's out attribute overrides the type in the typemap +	    if (cstypeout) +	      tm = cstypeout; +	    substituteClassname(cvariable_type, tm); +	    variable_type = tm; +	  } else { +	    Swig_warning(WARN_CSHARP_TYPEMAP_CSOUT_UNDEF, input_file, line_number, "No cstype typemap defined for %s\n", SwigType_str(cvariable_type, 0)); +	  } +	} +	const String *csattributes = Getattr(n, "feature:cs:attributes"); +	if (csattributes) +	  Printf(proxy_class_code, "  %s\n", csattributes); +	const String *methodmods = Getattr(n, "feature:cs:methodmodifiers"); +	if (!methodmods) +	  methodmods = (is_public(n) ? public_string : protected_string); +	Printf(proxy_class_code, "  %s %s%s %s {", methodmods, static_flag ? "static " : "", variable_type, variable_name); +      } +      generate_property_declaration_flag = false; + +      if (setter_flag) { +	// Setter method +	assert(last_parm);	// (last parameter is the only parameter for properties) +	SwigType *cvariable_type = Getattr(last_parm, "type"); +	Parm *variable_parm = NewParmNode(cvariable_type, n); +	if ((tm = Swig_typemap_lookup("csvarin", variable_parm, "", 0))) { +	  substituteClassname(cvariable_type, tm); +	  Replaceall(tm, "$csinput", "value"); +          Replaceall(tm, "$imfuncname", intermediary_function_name); +	  Replaceall(tm, "$imcall", imcall); +	  excodeSubstitute(n, tm, "csvarin", variable_parm); +	  Printf(proxy_class_code, "%s", tm); +	} else { +	  Swig_warning(WARN_CSHARP_TYPEMAP_CSOUT_UNDEF, input_file, line_number, "No csvarin typemap defined for %s\n", SwigType_str(cvariable_type, 0)); +	} +      } else { +	// Getter method +	if ((tm = Swig_typemap_lookup("csvarout", n, "", 0))) { +	  if (GetFlag(n, "feature:new")) +	    Replaceall(tm, "$owner", "true"); +	  else +	    Replaceall(tm, "$owner", "false"); +	  substituteClassname(t, tm); +          Replaceall(tm, "$imfuncname", intermediary_function_name); +	  Replaceall(tm, "$imcall", imcall); +	  excodeSubstitute(n, tm, "csvarout", n); +	  Printf(proxy_class_code, "%s", tm); +	} else { +	  Swig_warning(WARN_CSHARP_TYPEMAP_CSOUT_UNDEF, input_file, line_number, "No csvarout typemap defined for %s\n", SwigType_str(t, 0)); +	} +      } +    } else { +      // Normal function call +      Printf(function_code, " %s\n\n", tm ? (const String *) tm : empty_string); +      Printv(proxy_class_code, function_code, NIL); +    } + +    Delete(pre_code); +    Delete(post_code); +    Delete(terminator_code); +    Delete(function_code); +    Delete(return_type); +    Delete(imcall); +  } + +  /* ---------------------------------------------------------------------- +   * constructorHandler() +   * ---------------------------------------------------------------------- */ + +  virtual int constructorHandler(Node *n) { + +    ParmList *l = Getattr(n, "parms"); +    String *tm; +    Parm *p; +    int i; +    String *function_code = NewString(""); +    String *helper_code = NewString(""); // Holds code for the constructor helper method generated only when the csin typemap has code in the pre or post attributes +    String *helper_args = NewString(""); +    String *pre_code = NewString(""); +    String *post_code = NewString(""); +    String *terminator_code = NewString(""); +    String *im_return_type = NewString(""); +    bool feature_director = (parentNode(n) && Swig_directorclass(n)); + +    Language::constructorHandler(n); + +    // Wrappers not wanted for some methods where the parameters cannot be overloaded in C# +    if (Getattr(n, "overload:ignore")) +      return SWIG_OK; + +    if (proxy_flag) { +      String *overloaded_name = getOverloadedName(n); +      String *mangled_overname = Swig_name_construct(getNSpace(), overloaded_name); +      String *imcall = NewString(""); + +      const String *csattributes = Getattr(n, "feature:cs:attributes"); +      if (csattributes) { +	Printf(function_code, "  %s\n", csattributes); +	Printf(helper_code, "  %s\n", csattributes); +      } +      const String *methodmods = Getattr(n, "feature:cs:methodmodifiers"); +      methodmods = methodmods ? methodmods : (is_public(n) ? public_string : protected_string); + +      tm = Getattr(n, "tmap:imtype"); // typemaps were attached earlier to the node +      String *imtypeout = Getattr(n, "tmap:imtype:out");	// the type in the imtype typemap's out attribute overrides the type in the typemap +      if (imtypeout) +	tm = imtypeout; +      Printf(im_return_type, "%s", tm); + +      Printf(function_code, "  %s %s(", methodmods, proxy_class_name); +      Printf(helper_code, "  static private %s SwigConstruct%s(", im_return_type, proxy_class_name); + +      Printv(imcall, full_imclass_name, ".", mangled_overname, "(", NIL); + +      /* Attach the non-standard typemaps to the parameter list */ +      Swig_typemap_attach_parms("in", l, NULL); +      Swig_typemap_attach_parms("cstype", l, NULL); +      Swig_typemap_attach_parms("csin", l, NULL); + +      emit_mark_varargs(l); + +      int gencomma = 0; + +      /* Output each parameter */ +      for (i = 0, p = l; p; i++) { + +	/* Ignored varargs */ +	if (checkAttribute(p, "varargs:ignore", "1")) { +	  p = nextSibling(p); +	  continue; +	} + +	/* Ignored parameters */ +	if (checkAttribute(p, "tmap:in:numinputs", "0")) { +	  p = Getattr(p, "tmap:in:next"); +	  continue; +	} + +	SwigType *pt = Getattr(p, "type"); +	String *param_type = NewString(""); + +	/* Get the C# parameter type */ +	if ((tm = Getattr(p, "tmap:cstype"))) { +	  substituteClassname(pt, tm); +	  const String *inattributes = Getattr(p, "tmap:cstype:inattributes"); +	  Printf(param_type, "%s%s", inattributes ? inattributes : empty_string, tm); +	} else { +	  Swig_warning(WARN_CSHARP_TYPEMAP_CSWTYPE_UNDEF, input_file, line_number, "No cstype typemap defined for %s\n", SwigType_str(pt, 0)); +	} + +	if (gencomma) +	  Printf(imcall, ", "); + +	String *arg = makeParameterName(n, p, i, false); +        String *cshin = 0; + +	// Use typemaps to transform type used in C# wrapper function (in proxy class) to type used in PInvoke function (in intermediary class) +	if ((tm = Getattr(p, "tmap:csin"))) { +	  substituteClassname(pt, tm); +	  Replaceall(tm, "$csinput", arg); +          String *pre = Getattr(p, "tmap:csin:pre"); +          if (pre) { +            substituteClassname(pt, pre); +            Replaceall(pre, "$csinput", arg); +            if (Len(pre_code) > 0) +              Printf(pre_code, "\n"); +            Printv(pre_code, pre, NIL); +          } +          String *post = Getattr(p, "tmap:csin:post"); +          if (post) { +            substituteClassname(pt, post); +            Replaceall(post, "$csinput", arg); +            if (Len(post_code) > 0) +              Printf(post_code, "\n"); +            Printv(post_code, post, NIL); +          } +          String *terminator = Getattr(p, "tmap:csin:terminator"); +          if (terminator) { +            substituteClassname(pt, terminator); +            Replaceall(terminator, "$csinput", arg); +            if (Len(terminator_code) > 0) +              Insert(terminator_code, 0, "\n"); +            Insert(terminator_code, 0, terminator); +          } +          cshin = Getattr(p, "tmap:csin:cshin"); +          if (cshin) +            Replaceall(cshin, "$csinput", arg); +	  Printv(imcall, tm, NIL); +	} else { +	  Swig_warning(WARN_CSHARP_TYPEMAP_CSIN_UNDEF, input_file, line_number, "No csin typemap defined for %s\n", SwigType_str(pt, 0)); +	} + +	/* Add parameter to proxy function */ +	if (gencomma) { +	  Printf(function_code, ", "); +	  Printf(helper_code, ", "); +	  Printf(helper_args, ", "); +        } +	Printf(function_code, "%s %s", param_type, arg); +	Printf(helper_code, "%s %s", param_type, arg); +	Printf(helper_args, "%s", cshin ? cshin : arg); +	++gencomma; + +	Delete(cshin); +	Delete(arg); +	Delete(param_type); +	p = Getattr(p, "tmap:in:next"); +      } + +      Printf(imcall, ")"); + +      Printf(function_code, ")"); +      Printf(helper_code, ")"); + +      /* Insert the csconstruct typemap, doing the replacement for $directorconnect, as needed */ +      Hash *attributes = NewHash(); +      String *typemap_lookup_type = Getattr(getCurrentClass(), "classtypeobj"); +      String *construct_tm = Copy(typemapLookup(n, "csconstruct", typemap_lookup_type, +						WARN_CSHARP_TYPEMAP_CSCONSTRUCT_UNDEF, attributes)); +      if (construct_tm) { +	if (!feature_director) { +	  Replaceall(construct_tm, "$directorconnect", ""); +	} else { +	  String *connect_attr = Getattr(attributes, "tmap:csconstruct:directorconnect"); + +	  if (connect_attr) { +	    Replaceall(construct_tm, "$directorconnect", connect_attr); +	  } else { +	    Swig_warning(WARN_CSHARP_NO_DIRECTORCONNECT_ATTR, input_file, line_number, "\"directorconnect\" attribute missing in %s \"csconstruct\" typemap.\n", +			 Getattr(n, "name")); +	    Replaceall(construct_tm, "$directorconnect", ""); +	  } +	} + +	Printv(function_code, " ", construct_tm, NIL); +      } + +      excodeSubstitute(n, function_code, "csconstruct", attributes); + +      bool is_pre_code = Len(pre_code) > 0; +      bool is_post_code = Len(post_code) > 0; +      bool is_terminator_code = Len(terminator_code) > 0; +      if (is_pre_code || is_post_code || is_terminator_code) { +        Printf(helper_code, " {\n"); +        if (is_pre_code) { +          Printv(helper_code, pre_code, "\n", NIL); +        } +        if (is_post_code) { +          Printf(helper_code, "    try {\n"); +          Printv(helper_code, "      return ", imcall, ";\n", NIL); +          Printv(helper_code, "    } finally {\n", post_code, "\n    }", NIL); +        } else { +          Printv(helper_code, "    return ", imcall, ";", NIL); +        } +        if (is_terminator_code) { +          Printv(helper_code, "\n", terminator_code, NIL); +        } +        Printf(helper_code, "\n  }\n"); +        String *helper_name = NewStringf("%s.SwigConstruct%s(%s)", proxy_class_name, proxy_class_name, helper_args); +        String *im_outattributes = Getattr(n, "tmap:imtype:outattributes"); +        if (im_outattributes) +          Printf(proxy_class_code, "  %s\n", im_outattributes); +        Printv(proxy_class_code, helper_code, "\n", NIL); +        Replaceall(function_code, "$imcall", helper_name); +        Delete(helper_name); +      } else { +        Replaceall(function_code, "$imcall", imcall); +      } + +      Printv(proxy_class_code, function_code, "\n", NIL); + +      Delete(helper_args); +      Delete(im_return_type); +      Delete(pre_code); +      Delete(post_code); +      Delete(terminator_code); +      Delete(construct_tm); +      Delete(attributes); +      Delete(overloaded_name); +      Delete(imcall); +    } + +    return SWIG_OK; +  } + +  /* ---------------------------------------------------------------------- +   * destructorHandler() +   * ---------------------------------------------------------------------- */ + +  virtual int destructorHandler(Node *n) { +    Language::destructorHandler(n); +    String *symname = Getattr(n, "sym:name"); + +    if (proxy_flag) { +      Printv(destructor_call, full_imclass_name, ".", Swig_name_destroy(getNSpace(), symname), "(swigCPtr)", NIL); +      const String *methodmods = Getattr(n, "feature:cs:methodmodifiers"); +      if (methodmods) +	Setattr(getCurrentClass(), "destructmethodmodifiers", methodmods); +    } + +    return SWIG_OK; +  } + +  /* ---------------------------------------------------------------------- +   * membervariableHandler() +   * ---------------------------------------------------------------------- */ + +  virtual int membervariableHandler(Node *n) { + +    generate_property_declaration_flag = true; +    variable_name = Getattr(n, "sym:name"); +    wrapping_member_flag = true; +    variable_wrapper_flag = true; +    Language::membervariableHandler(n); +    wrapping_member_flag = false; +    variable_wrapper_flag = false; +    generate_property_declaration_flag = false; + +    Printf(proxy_class_code, "\n  }\n\n"); + +    return SWIG_OK; +  } + +  /* ---------------------------------------------------------------------- +   * staticmembervariableHandler() +   * ---------------------------------------------------------------------- */ + +  virtual int staticmembervariableHandler(Node *n) { + +    bool static_const_member_flag = (Getattr(n, "value") == 0); + +    generate_property_declaration_flag = true; +    variable_name = Getattr(n, "sym:name"); +    wrapping_member_flag = true; +    static_flag = true; +    Language::staticmembervariableHandler(n); +    wrapping_member_flag = false; +    static_flag = false; +    generate_property_declaration_flag = false; + +    if (static_const_member_flag) +      Printf(proxy_class_code, "\n  }\n\n"); + +    return SWIG_OK; +  } + +  /* ---------------------------------------------------------------------- +   * memberconstantHandler() +   * ---------------------------------------------------------------------- */ + +  virtual int memberconstantHandler(Node *n) { +    variable_name = Getattr(n, "sym:name"); +    wrapping_member_flag = true; +    Language::memberconstantHandler(n); +    wrapping_member_flag = false; +    return SWIG_OK; +  } + +  /* ----------------------------------------------------------------------------- +   * getOverloadedName() +   * ----------------------------------------------------------------------------- */ + +  String *getOverloadedName(Node *n) { + +    /* A C# HandleRef is used for all classes in the SWIG intermediary class. +     * The intermediary class methods are thus mangled when overloaded to give +     * a unique name. */ +    String *overloaded_name = NewStringf("%s", Getattr(n, "sym:name")); + +    if (Getattr(n, "sym:overloaded")) { +      Printv(overloaded_name, Getattr(n, "sym:overname"), NIL); +    } + +    return overloaded_name; +  } + +  /* ----------------------------------------------------------------------------- +   * moduleClassFunctionHandler() +   * ----------------------------------------------------------------------------- */ + +  void moduleClassFunctionHandler(Node *n) { +    SwigType *t = Getattr(n, "type"); +    ParmList *l = Getattr(n, "parms"); +    String *tm; +    Parm *p; +    Parm *last_parm = 0; +    int i; +    String *imcall = NewString(""); +    String *return_type = NewString(""); +    String *function_code = NewString(""); +    int num_arguments = 0; +    String *overloaded_name = getOverloadedName(n); +    String *func_name = NULL; +    bool setter_flag = false; +    String *pre_code = NewString(""); +    String *post_code = NewString(""); +    String *terminator_code = NewString(""); + +    if (l) { +      if (SwigType_type(Getattr(l, "type")) == T_VOID) { +	l = nextSibling(l); +      } +    } + +    /* Attach the non-standard typemaps to the parameter list */ +    Swig_typemap_attach_parms("cstype", l, NULL); +    Swig_typemap_attach_parms("csin", l, NULL); + +    /* Get return types */ +    if ((tm = Swig_typemap_lookup("cstype", n, "", 0))) { +      String *cstypeout = Getattr(n, "tmap:cstype:out");	// the type in the cstype typemap's out attribute overrides the type in the typemap +      if (cstypeout) +	tm = cstypeout; +      substituteClassname(t, tm); +      Printf(return_type, "%s", tm); +    } else { +      Swig_warning(WARN_CSHARP_TYPEMAP_CSWTYPE_UNDEF, input_file, line_number, "No cstype typemap defined for %s\n", SwigType_str(t, 0)); +    } + +    /* Change function name for global variables */ +    if (proxy_flag && global_variable_flag) { +      // Capitalize the first letter in the variable to create the getter/setter function name +      func_name = NewString(""); +      setter_flag = (Cmp(Getattr(n, "sym:name"), Swig_name_set(getNSpace(), variable_name)) == 0); +      if (setter_flag) +	Printf(func_name, "set"); +      else +	Printf(func_name, "get"); +      Putc(toupper((int) *Char(variable_name)), func_name); +      Printf(func_name, "%s", Char(variable_name) + 1); +      if (setter_flag) +        Swig_typemap_attach_parms("csvarin", l, NULL); +    } else { +      func_name = Copy(Getattr(n, "sym:name")); +    } + +    /* Start generating the function */ +    const String *outattributes = Getattr(n, "tmap:cstype:outattributes"); +    if (outattributes) +      Printf(function_code, "  %s\n", outattributes); +    const String *csattributes = Getattr(n, "feature:cs:attributes"); +    if (csattributes) +      Printf(function_code, "  %s\n", csattributes); +    const String *methodmods = Getattr(n, "feature:cs:methodmodifiers"); +    methodmods = methodmods ? methodmods : (is_public(n) ? public_string : protected_string); +    Printf(function_code, "  %s static %s %s(", methodmods, return_type, func_name); +    Printv(imcall, imclass_name, ".", overloaded_name, "(", NIL); + +    /* Get number of required and total arguments */ +    num_arguments = emit_num_arguments(l); + +    bool global_or_member_variable = global_variable_flag || (wrapping_member_flag && !enum_constant_flag); +    int gencomma = 0; + +    /* Output each parameter */ +    for (i = 0, p = l; i < num_arguments; i++) { + +      /* Ignored parameters */ +      while (checkAttribute(p, "tmap:in:numinputs", "0")) { +	p = Getattr(p, "tmap:in:next"); +      } + +      SwigType *pt = Getattr(p, "type"); +      String *param_type = NewString(""); +      last_parm = p; + +      /* Get the C# parameter type */ +      if ((tm = Getattr(p, "tmap:cstype"))) { +	substituteClassname(pt, tm); +	const String *inattributes = Getattr(p, "tmap:cstype:inattributes"); +	Printf(param_type, "%s%s", inattributes ? inattributes : empty_string, tm); +      } else { +	Swig_warning(WARN_CSHARP_TYPEMAP_CSWTYPE_UNDEF, input_file, line_number, "No cstype typemap defined for %s\n", SwigType_str(pt, 0)); +      } + +      if (gencomma) +	Printf(imcall, ", "); + +      String *arg = makeParameterName(n, p, i, global_or_member_variable); + +      // Use typemaps to transform type used in C# wrapper function (in proxy class) to type used in PInvoke function (in intermediary class) +      if ((tm = Getattr(p, "tmap:csin"))) { +	substituteClassname(pt, tm); +	Replaceall(tm, "$csinput", arg); +	String *pre = Getattr(p, "tmap:csin:pre"); +	if (pre) { +	  substituteClassname(pt, pre); +	  Replaceall(pre, "$csinput", arg); +          if (Len(pre_code) > 0) +            Printf(pre_code, "\n"); +	  Printv(pre_code, pre, NIL); +	} +	String *post = Getattr(p, "tmap:csin:post"); +	if (post) { +	  substituteClassname(pt, post); +	  Replaceall(post, "$csinput", arg); +          if (Len(post_code) > 0) +            Printf(post_code, "\n"); +	  Printv(post_code, post, NIL); +	} +        String *terminator = Getattr(p, "tmap:csin:terminator"); +        if (terminator) { +          substituteClassname(pt, terminator); +          Replaceall(terminator, "$csinput", arg); +          if (Len(terminator_code) > 0) +            Insert(terminator_code, 0, "\n"); +          Insert(terminator_code, 0, terminator); +        } +	Printv(imcall, tm, NIL); +      } else { +	Swig_warning(WARN_CSHARP_TYPEMAP_CSIN_UNDEF, input_file, line_number, "No csin typemap defined for %s\n", SwigType_str(pt, 0)); +      } + +      /* Add parameter to module class function */ +      if (gencomma >= 2) +	Printf(function_code, ", "); +      gencomma = 2; +      Printf(function_code, "%s %s", param_type, arg); + +      p = Getattr(p, "tmap:in:next"); +      Delete(arg); +      Delete(param_type); +    } + +    Printf(imcall, ")"); +    Printf(function_code, ")"); + +    // Transform return type used in PInvoke function (in intermediary class) to type used in C# wrapper function (in module class) +    if ((tm = Swig_typemap_lookup("csout", n, "", 0))) { +      excodeSubstitute(n, tm, "csout", n); +      bool is_pre_code = Len(pre_code) > 0; +      bool is_post_code = Len(post_code) > 0; +      bool is_terminator_code = Len(terminator_code) > 0; +      if (is_pre_code || is_post_code || is_terminator_code) { +        Replaceall(tm, "\n ", "\n   "); // add extra indentation to code in typemap +        if (is_post_code) { +          Insert(tm, 0, "\n    try "); +          Printv(tm, " finally {\n", post_code, "\n    }", NIL); +        } else { +          Insert(tm, 0, "\n    "); +        } +        if (is_pre_code) { +          Insert(tm, 0, pre_code); +          Insert(tm, 0, "\n"); +        } +        if (is_terminator_code) { +          Printv(tm, "\n", terminator_code, NIL); +        } +	Insert(tm, 0, "{"); +	Printf(tm, "\n  }"); +      } +      if (GetFlag(n, "feature:new")) +	Replaceall(tm, "$owner", "true"); +      else +	Replaceall(tm, "$owner", "false"); +      substituteClassname(t, tm); +      Replaceall(tm, "$imfuncname", overloaded_name); +      Replaceall(tm, "$imcall", imcall); +    } else { +      Swig_warning(WARN_CSHARP_TYPEMAP_CSOUT_UNDEF, input_file, line_number, "No csout typemap defined for %s\n", SwigType_str(t, 0)); +    } + +    if (proxy_flag && global_variable_flag) { +      // Properties +      if (generate_property_declaration_flag) {	// Ensure the declaration is generated just once should the property contain both a set and get +	// Get the C# variable type - obtained differently depending on whether a setter is required. +	String *variable_type = return_type; +	if (setter_flag) { +	  p = last_parm;	// (last parameter is the only parameter for properties) +	  SwigType *pt = Getattr(p, "type"); +	  if ((tm = Getattr(p, "tmap:cstype"))) { +	    substituteClassname(pt, tm); +            String *cstypeout = Getattr(p, "tmap:cstype:out");	// the type in the cstype typemap's out attribute overrides the type in the typemap +	    variable_type = cstypeout ? cstypeout : tm; +	  } else { +	    Swig_warning(WARN_CSHARP_TYPEMAP_CSOUT_UNDEF, input_file, line_number, "No csvarin typemap defined for %s\n", SwigType_str(pt, 0)); +	  } +	} +	const String *csattributes = Getattr(n, "feature:cs:attributes"); +	if (csattributes) +	  Printf(module_class_code, "  %s\n", csattributes); +	const String *methodmods = Getattr(n, "feature:cs:methodmodifiers"); +	if (!methodmods) +	  methodmods = (is_public(n) ? public_string : protected_string); +	Printf(module_class_code, "  %s static %s %s {", methodmods, variable_type, variable_name); +      } +      generate_property_declaration_flag = false; + +      if (setter_flag) { +	// Setter method +	p = last_parm;		// (last parameter is the only parameter for properties) +	SwigType *pt = Getattr(p, "type"); +	if ((tm = Getattr(p, "tmap:csvarin"))) { +	  substituteClassname(pt, tm); +	  Replaceall(tm, "$csinput", "value"); +	  Replaceall(tm, "$imfuncname", overloaded_name); +	  Replaceall(tm, "$imcall", imcall); +	  excodeSubstitute(n, tm, "csvarin", p); +	  Printf(module_class_code, "%s", tm); +	} else { +	  Swig_warning(WARN_CSHARP_TYPEMAP_CSOUT_UNDEF, input_file, line_number, "No csvarin typemap defined for %s\n", SwigType_str(pt, 0)); +	} +      } else { +	// Getter method +	if ((tm = Swig_typemap_lookup("csvarout", n, "", 0))) { +	  if (GetFlag(n, "feature:new")) +	    Replaceall(tm, "$owner", "true"); +	  else +	    Replaceall(tm, "$owner", "false"); +	  substituteClassname(t, tm); +	  Replaceall(tm, "$imfuncname", overloaded_name); +	  Replaceall(tm, "$imcall", imcall); +	  excodeSubstitute(n, tm, "csvarout", n); +	  Printf(module_class_code, "%s", tm); +	} else { +	  Swig_warning(WARN_CSHARP_TYPEMAP_CSOUT_UNDEF, input_file, line_number, "No csvarout typemap defined for %s\n", SwigType_str(t, 0)); +	} +      } +    } else { +      // Normal function call +      Printf(function_code, " %s\n\n", tm ? (const String *) tm : empty_string); +      Printv(module_class_code, function_code, NIL); +    } + +    Delete(pre_code); +    Delete(post_code); +    Delete(terminator_code); +    Delete(function_code); +    Delete(return_type); +    Delete(imcall); +    Delete(func_name); +  } + +  /*---------------------------------------------------------------------- +   * replaceSpecialVariables() +   *--------------------------------------------------------------------*/ + +  virtual void replaceSpecialVariables(String *method, String *tm, Parm *parm) { +    (void)method; +    SwigType *type = Getattr(parm, "type"); +    substituteClassname(type, tm); +  } + +  /*---------------------------------------------------------------------- +   * decodeEnumFeature() +   * Decode the possible enum features, which are one of: +   *   %csenum(simple) +   *   %csenum(typeunsafe) - default +   *   %csenum(typesafe) +   *   %csenum(proper) +   *--------------------------------------------------------------------*/ + +  EnumFeature decodeEnumFeature(Node *n) { +    EnumFeature enum_feature = TypeunsafeEnum; +    String *feature = Getattr(n, "feature:cs:enum"); +    if (feature) { +      if (Cmp(feature, "simple") == 0) +	enum_feature = SimpleEnum; +      else if (Cmp(feature, "typesafe") == 0) +	enum_feature = TypesafeEnum; +      else if (Cmp(feature, "proper") == 0) +	enum_feature = ProperEnum; +    } +    return enum_feature; +  } + +  /* ----------------------------------------------------------------------- +   * enumValue() +   * This method will return a string with an enum value to use in C# generated +   * code. If the %csconst feature is not used, the string will contain the intermediary +   * class call to obtain the enum value. The intermediary class and PINVOKE methods to obtain +   * the enum value will be generated. Otherwise the C/C++ enum value will be used if there +   * is one and hopefully it will compile as C# code - e.g. 20 as in: enum E{e=20}; +   * The %csconstvalue feature overrides all other ways to generate the constant value. +   * The caller must delete memory allocated for the returned string. +   * ------------------------------------------------------------------------ */ + +  String *enumValue(Node *n) { +    String *symname = Getattr(n, "sym:name"); + +    // Check for the %csconstvalue feature +    String *value = Getattr(n, "feature:cs:constvalue"); + +    if (!value) { +      // The %csconst feature determines how the constant value is obtained +      int const_feature_flag = GetFlag(n, "feature:cs:const"); + +      if (const_feature_flag) { +	// Use the C syntax to make a true C# constant and hope that it compiles as C# code +	value = Getattr(n, "enumvalue") ? Copy(Getattr(n, "enumvalue")) : Copy(Getattr(n, "enumvalueex")); +      } else { +	String *newsymname = 0; +	if (!getCurrentClass() || !proxy_flag) { +	  String *enumClassPrefix = getEnumClassPrefix(); +	  if (enumClassPrefix) { +	    // A global scoped enum +	    newsymname = Swig_name_member(0, enumClassPrefix, symname); +	    symname = newsymname; +	  } +	} + +	// Get the enumvalue from a PINVOKE call +	if (!getCurrentClass() || !cparse_cplusplus || !proxy_flag) { +	  // Strange hack to change the name +	  Setattr(n, "name", Getattr(n, "value"));	/* for wrapping of enums in a namespace when emit_action is used */ +	  constantWrapper(n); +	  value = NewStringf("%s.%s()", full_imclass_name ? full_imclass_name : imclass_name, Swig_name_get(getNSpace(), symname)); +	} else { +	  memberconstantHandler(n); +	  value = NewStringf("%s.%s()", full_imclass_name ? full_imclass_name : imclass_name, Swig_name_get(getNSpace(), Swig_name_member(0, getEnumClassPrefix(), symname))); +	} +      } +    } +    return value; +  } + +  /* ----------------------------------------------------------------------------- +   * getEnumName() +   * ----------------------------------------------------------------------------- */ + +  String *getEnumName(SwigType *t) { +    Node *enumname = NULL; +    Node *n = enumLookup(t); +    if (n) { +      enumname = Getattr(n, "enumname"); +      if (!enumname) { +	String *symname = Getattr(n, "sym:name"); +	if (symname) { +	  // Add in class scope when referencing enum if not a global enum +	  String *scopename_prefix = Swig_scopename_prefix(Getattr(n, "name")); +	  String *proxyname = 0; +	  if (scopename_prefix) { +	    proxyname = getProxyName(scopename_prefix); +	  } +	  if (proxyname) { +	    enumname = NewStringf("%s.%s", proxyname, symname); +	  } else { +	    // global enum or enum in a namespace +	    String *nspace = Getattr(n, "sym:nspace"); +	    if (nspace) { +	      if (namespce) +		enumname = NewStringf("%s.%s.%s", namespce, nspace, symname); +	      else +		enumname = NewStringf("%s.%s", nspace, symname); +	    } else { +	      enumname = Copy(symname); +	    } +	  } +	  Setattr(n, "enumname", enumname); +	  Delete(enumname); +	  Delete(scopename_prefix); +	} +      } +    } + +    return enumname; +  } + +  /* ----------------------------------------------------------------------------- +   * substituteClassname() +   * +   * Substitute the special variable $csclassname with the proxy class name for classes/structs/unions  +   * that SWIG knows about. Also substitutes enums with enum name. +   * Otherwise use the $descriptor name for the C# class name. Note that the $&csclassname substitution +   * is the same as a $&descriptor substitution, ie one pointer added to descriptor name. +   * Inputs: +   *   pt - parameter type +   *   tm - typemap contents that might contain the special variable to be replaced +   * Outputs: +   *   tm - typemap contents complete with the special variable substitution +   * Return: +   *   substitution_performed - flag indicating if a substitution was performed +   * ----------------------------------------------------------------------------- */ + +  bool substituteClassname(SwigType *pt, String *tm) { +    bool substitution_performed = false; +    SwigType *type = Copy(SwigType_typedef_resolve_all(pt)); +    SwigType *strippedtype = SwigType_strip_qualifiers(type); + +    if (Strstr(tm, "$csclassname")) { +      SwigType *classnametype = Copy(strippedtype); +      substituteClassnameSpecialVariable(classnametype, tm, "$csclassname"); +      substitution_performed = true; +      Delete(classnametype); +    } +    if (Strstr(tm, "$*csclassname")) { +      SwigType *classnametype = Copy(strippedtype); +      Delete(SwigType_pop(classnametype)); +      if (Len(classnametype) > 0) { +	substituteClassnameSpecialVariable(classnametype, tm, "$*csclassname"); +	substitution_performed = true; +      } +      Delete(classnametype); +    } +    if (Strstr(tm, "$&csclassname")) { +      SwigType *classnametype = Copy(strippedtype); +      SwigType_add_pointer(classnametype); +      substituteClassnameSpecialVariable(classnametype, tm, "$&csclassname"); +      substitution_performed = true; +      Delete(classnametype); +    } +    if (Strstr(tm, "$csinterfacename")) { +      SwigType *interfacenametype = Copy(strippedtype); +      substituteInterfacenameSpecialVariable(interfacenametype, tm, "$csinterfacename", true); +      substitution_performed = true; +      Delete(interfacenametype); +    } +    if (Strstr(tm, "$*csinterfacename")) { +      SwigType *interfacenametype = Copy(strippedtype); +      Delete(SwigType_pop(interfacenametype)); +      if (Len(interfacenametype) > 0) { +	substituteInterfacenameSpecialVariable(interfacenametype, tm, "$*csinterfacename", true); +	substitution_performed = true; +      } +      Delete(interfacenametype); +    } +    if (Strstr(tm, "$&csinterfacename")) { +      SwigType *interfacenametype = Copy(strippedtype); +      SwigType_add_pointer(interfacenametype); +      substituteInterfacenameSpecialVariable(interfacenametype, tm, "$&csinterfacename", true); +      substitution_performed = true; +      Delete(interfacenametype); +    } +    if (Strstr(tm, "$interfacename")) { +      SwigType *interfacenametype = Copy(strippedtype); +      substituteInterfacenameSpecialVariable(interfacenametype, tm, "$interfacename", false); +      substitution_performed = true; +      Delete(interfacenametype); +    } +    if (Strstr(tm, "$*interfacename")) { +      SwigType *interfacenametype = Copy(strippedtype); +      Delete(SwigType_pop(interfacenametype)); +      if (Len(interfacenametype) > 0) { +	substituteInterfacenameSpecialVariable(interfacenametype, tm, "$*interfacename", false); +	substitution_performed = true; +      } +      Delete(interfacenametype); +    } +    if (Strstr(tm, "$&interfacename")) { +      SwigType *interfacenametype = Copy(strippedtype); +      SwigType_add_pointer(interfacenametype); +      substituteInterfacenameSpecialVariable(interfacenametype, tm, "$&interfacename", false); +      substitution_performed = true; +      Delete(interfacenametype); +    } + +    Delete(strippedtype); +    Delete(type); + +    return substitution_performed; +  } + +  /* ----------------------------------------------------------------------------- +   * substituteClassnameSpecialVariable() +   * ----------------------------------------------------------------------------- */ + +  void substituteClassnameSpecialVariable(SwigType *classnametype, String *tm, const char *classnamespecialvariable) { +    String *replacementname; +    if (SwigType_isenum(classnametype)) { +      String *enumname = getEnumName(classnametype); +      if (enumname) { +	replacementname = Copy(enumname); +      } else { +	bool anonymous_enum = (Cmp(classnametype, "enum ") == 0); +	if (anonymous_enum) { +	  replacementname = NewString("int"); +	} else { +	  // An unknown enum - one that has not been parsed (neither a C enum forward reference nor a definition) or an ignored enum +	  replacementname = NewStringf("SWIGTYPE%s", SwigType_manglestr(classnametype)); +	  Replace(replacementname, "enum ", "", DOH_REPLACE_ANY); +	  Setattr(swig_types_hash, replacementname, classnametype); +	} +      } +    } else { +      String *classname = getProxyName(classnametype); // getProxyName() works for pointers to classes too +      if (classname) { +	replacementname = Copy(classname); +      } else { +	// use $descriptor if SWIG does not know anything about this type. Note that any typedefs are resolved. +	replacementname = NewStringf("SWIGTYPE%s", SwigType_manglestr(classnametype)); + +	// Add to hash table so that the type wrapper classes can be created later +	Setattr(swig_types_hash, replacementname, classnametype); +      } +    } +    Replaceall(tm, classnamespecialvariable, replacementname); + +    Delete(replacementname); +  } + +  /* ----------------------------------------------------------------------------- +   * substituteInterfacenameSpecialVariable() +   * ----------------------------------------------------------------------------- */ + +  void substituteInterfacenameSpecialVariable(SwigType *interfacenametype, String *tm, const char *interfacenamespecialvariable, bool qualified) { + +    String *interfacename = getInterfaceName(interfacenametype, qualified); +    if (interfacename) { +      String *replacementname = Copy(interfacename); +      Replaceall(tm, interfacenamespecialvariable, replacementname); +      Delete(replacementname); +    } +  } + +  /* ----------------------------------------------------------------------------- +   * emitTypeWrapperClass() +   * ----------------------------------------------------------------------------- */ + +  void emitTypeWrapperClass(String *classname, SwigType *type) { +    Node *n = NewHash(); +    Setfile(n, input_file); +    Setline(n, line_number); + +    String *swigtype = NewString(""); +    File *f_swigtype = getOutputFile(SWIG_output_directory(), classname); + +    addOpenNamespace(0, f_swigtype); + +    // Pure C# baseclass and interfaces +    const String *pure_baseclass = typemapLookup(n, "csbase", type, WARN_NONE); +    const String *pure_interfaces = typemapLookup(n, "csinterfaces", type, WARN_NONE); + +    // Emit the class +    Printv(swigtype, typemapLookup(n, "csimports", type, WARN_NONE),	// Import statements +	   "\n", NIL); + +    // Class attributes +    const String *csattributes = typemapLookup(n, "csattributes", type, WARN_NONE); +    if (csattributes && *Char(csattributes)) +      Printf(swigtype, "%s\n", csattributes); + +    Printv(swigtype, typemapLookup(n, "csclassmodifiers", type, WARN_CSHARP_TYPEMAP_CLASSMOD_UNDEF),	// Class modifiers +	   " $csclassname",	// Class name and base class +	   (*Char(pure_baseclass) || *Char(pure_interfaces)) ? " : " : "", pure_baseclass, ((*Char(pure_baseclass)) && *Char(pure_interfaces)) ?	// Interfaces +	   ", " : "", pure_interfaces, " {", typemapLookup(n, "csbody", type, WARN_CSHARP_TYPEMAP_CSBODY_UNDEF),	// main body of class +	   typemapLookup(n, "cscode", type, WARN_NONE),	// extra C# code +	   "}\n", NIL); + +    Replaceall(swigtype, "$csclassname", classname); +    Replaceall(swigtype, "$module", module_class_name); +    Replaceall(swigtype, "$imclassname", imclass_name); +    Replaceall(swigtype, "$dllimport", dllimport); + +    // For unknown enums +    Replaceall(swigtype, "$enumvalues", ""); + +    Printv(f_swigtype, swigtype, NIL); + +    addCloseNamespace(0, f_swigtype); +    if (f_swigtype != f_single_out) +      Delete(f_swigtype); +    f_swigtype = NULL; +    Delete(swigtype); +    Delete(n); +  } + +  /* ----------------------------------------------------------------------------- +   * typemapLookup() +   * n - for input only and must contain info for Getfile(n) and Getline(n) to work +   * tmap_method - typemap method name +   * type - typemap type to lookup +   * warning - warning number to issue if no typemaps found +   * typemap_attributes - the typemap attributes are attached to this node and will  +   *   also be used for temporary storage if non null +   * return is never NULL, unlike Swig_typemap_lookup() +   * ----------------------------------------------------------------------------- */ + +  const String *typemapLookup(Node *n, const_String_or_char_ptr tmap_method, SwigType *type, int warning, Node *typemap_attributes = 0) { +    Node *node = !typemap_attributes ? NewHash() : typemap_attributes; +    Setattr(node, "type", type); +    Setfile(node, Getfile(n)); +    Setline(node, Getline(n)); +    const String *tm = Swig_typemap_lookup(tmap_method, node, "", 0); +    if (!tm) { +      tm = empty_string; +      if (warning != WARN_NONE) +	Swig_warning(warning, Getfile(n), Getline(n), "No %s typemap defined for %s\n", tmap_method, SwigType_str(type, 0)); +    } +    if (!typemap_attributes) +      Delete(node); +    return tm; +  } + +  /* ----------------------------------------------------------------------------- +   * typemapExists() +   * n - for input only and must contain info for Getfile(n) and Getline(n) to work +   * tmap_method - typemap method name +   * type - typemap type to lookup +   * returns found typemap or NULL if not found +   * ----------------------------------------------------------------------------- */ + +  const String *typemapExists(Node *n, const_String_or_char_ptr tmap_method, SwigType *type) { +    Node *node = NewHash(); +    Setattr(node, "type", type); +    Setfile(node, Getfile(n)); +    Setline(node, Getline(n)); +    const String *tm = Swig_typemap_lookup(tmap_method, node, "", 0); +    Delete(node); +    return tm; +  } + +  /* ----------------------------------------------------------------------------- +   * canThrow() +   * Determine whether the code in the typemap can throw a C# exception. +   * If so, note it for later when excodeSubstitute() is called. +   * ----------------------------------------------------------------------------- */ + +  void canThrow(Node *n, const String *typemap, Node *parameter) { +    String *canthrow_attribute = NewStringf("tmap:%s:canthrow", typemap); +    String *canthrow = Getattr(parameter, canthrow_attribute); +    if (canthrow) +      Setattr(n, "csharp:canthrow", "1"); +    Delete(canthrow_attribute); +  } + +  /* ----------------------------------------------------------------------------- +   * excodeSubstitute() +   * If a method can throw a C# exception, additional exception code is added to +   * check for the pending exception so that it can then throw the exception. The +   * $excode special variable is replaced by the exception code in the excode +   * typemap attribute. +   * ----------------------------------------------------------------------------- */ + +  void excodeSubstitute(Node *n, String *code, const String *typemap, Node *parameter) { +    String *excode_attribute = NewStringf("tmap:%s:excode", typemap); +    String *excode = Getattr(parameter, excode_attribute); +    if (Getattr(n, "csharp:canthrow")) { +      int count = Replaceall(code, "$excode", excode); +      if (count < 1 || !excode) { +	Swig_warning(WARN_CSHARP_EXCODE, input_file, line_number, +		     "C# exception may not be thrown - no $excode or excode attribute in '%s' typemap.\n", typemap); +      } +    } else { +      Replaceall(code, "$excode", empty_string); +    } +    Delete(excode_attribute); +  } + +  /* ----------------------------------------------------------------------------- +   * addOpenNamespace() +   * ----------------------------------------------------------------------------- */ + +  void addOpenNamespace(const String *nspace, File *file) { +    if (namespce || nspace) { +      Printf(file, "namespace "); +      if (namespce) +	Printv(file, namespce, nspace ? "." : "", NIL); +      if (nspace) +	Printv(file, nspace, NIL); +      Printf(file, " {\n"); +    } +  } + +  /* ----------------------------------------------------------------------------- +   * addCloseNamespace() +   * ----------------------------------------------------------------------------- */ + +  void addCloseNamespace(const String *nspace, File *file) { +    if (namespce || nspace) +      Printf(file, "\n}\n"); +  } + +  /* ----------------------------------------------------------------------------- +   * outputDirectory() +   * +   * Return the directory to use for generating C# classes/enums and create the +   * subdirectory (does not create if language specific outdir does not exist). +   * ----------------------------------------------------------------------------- */ + +  String *outputDirectory(String *nspace) { +    String *output_directory = Copy(SWIG_output_directory()); +    if (nspace) { +      String *nspace_subdirectory = Copy(nspace); +      Replaceall(nspace_subdirectory, ".", SWIG_FILE_DELIMITER); +      String *newdir_error = Swig_new_subdirectory(output_directory, nspace_subdirectory); +      if (newdir_error) { +	Printf(stderr, "%s\n", newdir_error); +	Delete(newdir_error); +	Exit(EXIT_FAILURE); +      } +      Printv(output_directory, nspace_subdirectory, SWIG_FILE_DELIMITER, 0); +      Delete(nspace_subdirectory); +    } +    return output_directory; +  } + +  /*---------------------------------------------------------------------- +   * Start of director methods +   *--------------------------------------------------------------------*/ + +#if 0 +  /*---------------------------------------------------------------------- +   * emitDirectorUpcalls() +   *--------------------------------------------------------------------*/ + +  void emitDirectorUpcalls() { +    if (n_dmethods) { +      Wrapper *w = NewWrapper(); +      String *dmethod_data = NewString(""); +      int n_methods = 0; +      Iterator udata_iter; + +      udata_iter = First(dmethods_seq); +      while (udata_iter.item) { +	UpcallData *udata = udata_iter.item; +	Printf(dmethod_data, "  { \"%s\", \"%s\" }", Getattr(udata, "imclass_method"), Getattr(udata, "imclass_fdesc")); +	++n_methods; + +	udata_iter = Next(udata_iter); + +	if (udata_iter.item) +	  Putc(',', dmethod_data); +	Putc('\n', dmethod_data); +      } + + +      Wrapper_print(w, f_wrappers); +      Delete(dmethod_data); +      Delete(swig_module_init); +      DelWrapper(w); +    } +  } +#endif + +  /*---------------------------------------------------------------------- +   * emitDirectorExtraMethods() +   * +   * This is where the director connect method is generated. +   *--------------------------------------------------------------------*/ +  void emitDirectorExtraMethods(Node *n) { +    if (!Swig_directorclass(n)) +      return; + +    // Output the director connect method: +    String *norm_name = SwigType_namestr(Getattr(n, "name")); +    String *dirclassname = directorClassName(n); +    String *swig_director_connect = Swig_name_member(getNSpace(), getClassPrefix(), "director_connect"); +    String *wname = Swig_name_wrapper(swig_director_connect); +    String *sym_name = Getattr(n, "sym:name"); +    String *qualified_classname = Copy(sym_name); +    String *nspace = getNSpace(); +    String *dirClassName = directorClassName(n); +    String *smartptr = Getattr(n, "feature:smartptr"); +    if (!GetFlag(n, "feature:flatnested")) { +      for (Node *outer_class = Getattr(n, "nested:outer"); outer_class; outer_class = Getattr(outer_class, "nested:outer")) { + +	Push(qualified_classname, "."); +	Push(qualified_classname, Getattr(outer_class, "sym:name")); +      } +    } +    if (nspace) +      Insert(qualified_classname, 0, NewStringf("%s.", nspace)); + +    Printv(imclass_class_code, "\n  [global::System.Runtime.InteropServices.DllImport(\"", dllimport, "\", EntryPoint=\"", wname, "\")]\n", NIL); +    Printf(imclass_class_code, "  public static extern void %s(global::System.Runtime.InteropServices.HandleRef jarg1", swig_director_connect); + +    Wrapper *code_wrap = NewWrapper(); +    Printf(code_wrap->def, "SWIGEXPORT void SWIGSTDCALL %s(void *objarg", wname); + +    if (smartptr) { +      Printf(code_wrap->code, "  %s *obj = (%s *)objarg;\n", smartptr, smartptr); +      Printf(code_wrap->code, "  // Keep a local instance of the smart pointer around while we are using the raw pointer\n"); +      Printf(code_wrap->code, "  // Avoids using smart pointer specific API.\n"); +      Printf(code_wrap->code, "  %s *director = static_cast<%s *>(obj->operator->());\n", dirClassName, dirClassName); +    } else { +      Printf(code_wrap->code, "  %s *obj = (%s *)objarg;\n", norm_name, norm_name); +      Printf(code_wrap->code, "  %s *director = static_cast<%s *>(obj);\n", dirClassName, dirClassName); +    } + +    Printf(code_wrap->code, "  director->swig_connect_director("); + +    for (int i = first_class_dmethod; i < curr_class_dmethod; ++i) { +      UpcallData *udata = Getitem(dmethods_seq, i); +      String *methid = Getattr(udata, "class_methodidx"); + +      Printf(code_wrap->def, ", "); +      if (i != first_class_dmethod) +	Printf(code_wrap->code, ", "); +      Printf(code_wrap->def, "%s::SWIG_Callback%s_t callback%s", dirclassname, methid, methid); +      Printf(code_wrap->code, "callback%s", methid); +      Printf(imclass_class_code, ", %s.SwigDelegate%s_%s delegate%s", qualified_classname, sym_name, methid, methid); +    } + +    Printf(code_wrap->def, ") {\n"); +    Printf(code_wrap->code, ");\n"); +    Printf(imclass_class_code, ");\n"); +    Printf(code_wrap->code, "}\n"); + +    Wrapper_print(code_wrap, f_wrappers); +    DelWrapper(code_wrap); + +    Delete(wname); +    Delete(swig_director_connect); +    Delete(qualified_classname); +    Delete(dirclassname); +  } + +  /* --------------------------------------------------------------- +   * classDirectorMethod() +   * +   * Emit a virtual director method to pass a method call on to the  +   * underlying C# object. +   * +   * --------------------------------------------------------------- */ + +  int classDirectorMethod(Node *n, Node *parent, String *super) { +    String *classname = Getattr(parent, "sym:name"); +    String *c_classname = Getattr(parent, "name"); +    String *name = Getattr(n, "name"); +    String *symname = Getattr(n, "sym:name"); +    SwigType *returntype = Getattr(n, "type"); +    String *overloaded_name = getOverloadedName(n); +    String *storage = Getattr(n, "storage"); +    String *value = Getattr(n, "value"); +    String *decl = Getattr(n, "decl"); +    String *declaration = NewString(""); +    String *pre_code = NewString(""); +    String *post_code = NewString(""); +    String *terminator_code = NewString(""); +    String *tm; +    Parm *p; +    int i; +    Wrapper *w = NewWrapper(); +    ParmList *l = Getattr(n, "parms"); +    bool is_void = !(Cmp(returntype, "void")); +    String *qualified_return = 0; +    bool pure_virtual = (!(Cmp(storage, "virtual")) && !(Cmp(value, "0"))); +    int status = SWIG_OK; +    bool output_director = true; +    String *dirclassname = directorClassName(parent); +    String *qualified_name = NewStringf("%s::%s", dirclassname, name); +    SwigType *c_ret_type = NULL; +    String *jupcall_args = NewString(""); +    String *imclass_dmethod; +    String *callback_typedef_parms = NewString(""); +    String *delegate_parms = NewString(""); +    String *proxy_method_types = NewString(""); +    String *callback_def = NewString(""); +    String *callback_code = NewString(""); +    String *imcall_args = NewString(""); +    bool ignored_method = GetFlag(n, "feature:ignore") ? true : false; + +    // Kludge Alert: functionWrapper sets sym:overload properly, but it +    // isn't at this point, so we have to manufacture it ourselves. At least +    // we're consistent with the sym:overload name in functionWrapper. (?? when +    // does the overloaded method name get set?) + +    imclass_dmethod = NewStringf("SwigDirector_%s", Swig_name_member(getNSpace(), getClassPrefix(), overloaded_name)); + +    qualified_return = SwigType_rcaststr(returntype, "c_result"); + +    if (!is_void && (!ignored_method || pure_virtual)) { +      if (!SwigType_isclass(returntype)) { +	if (!(SwigType_ispointer(returntype) || SwigType_isreference(returntype))) { +	  String *construct_result = NewStringf("= SwigValueInit< %s >()", SwigType_lstr(returntype, 0)); +	  Wrapper_add_localv(w, "c_result", SwigType_lstr(returntype, "c_result"), construct_result, NIL); +	  Delete(construct_result); +	} else { +	  String *base_typename = SwigType_base(returntype); +	  String *resolved_typename = SwigType_typedef_resolve_all(base_typename); +	  Symtab *symtab = Getattr(n, "sym:symtab"); +	  Node *typenode = Swig_symbol_clookup(resolved_typename, symtab); + +	  if (SwigType_ispointer(returntype) || (typenode && Getattr(typenode, "abstracts"))) { +	    /* initialize pointers to something sane. Same for abstract +	       classes when a reference is returned. */ +	    Wrapper_add_localv(w, "c_result", SwigType_lstr(returntype, "c_result"), "= 0", NIL); +	  } else { +	    /* If returning a reference, initialize the pointer to a sane +	       default - if a C# exception occurs, then the pointer returns +	       something other than a NULL-initialized reference. */ +	    SwigType *noref_type = SwigType_del_reference(Copy(returntype)); +	    String *noref_ltype = SwigType_lstr(noref_type, 0); +	    String *return_ltype = SwigType_lstr(returntype, 0); + +	    Wrapper_add_localv(w, "result_default", "static", noref_ltype, "result_default", NIL); +	    Wrapper_add_localv(w, "c_result", return_ltype, "c_result", NIL); +	    Printf(w->code, "result_default = SwigValueInit< %s >();\n", noref_ltype); +	    Printf(w->code, "c_result = &result_default;\n"); +	    Delete(return_ltype); +	    Delete(noref_ltype); +	    Delete(noref_type); +	  } + +	  Delete(base_typename); +	  Delete(resolved_typename); +	} +      } else { +	SwigType *vt; + +	vt = cplus_value_type(returntype); +	if (!vt) { +	  Wrapper_add_localv(w, "c_result", SwigType_lstr(returntype, "c_result"), NIL); +	} else { +	  Wrapper_add_localv(w, "c_result", SwigType_lstr(vt, "c_result"), NIL); +	  Delete(vt); +	} +      } +    } + +    /* Create the intermediate class wrapper */ +    tm = Swig_typemap_lookup("imtype", n, "", 0); +    if (tm) { +      String *imtypeout = Getattr(n, "tmap:imtype:out");	// the type in the imtype typemap's out attribute overrides the type in the typemap +      if (imtypeout) +	tm = imtypeout; +      const String *im_directoroutattributes = Getattr(n, "tmap:imtype:directoroutattributes"); +      if (im_directoroutattributes) { +	Printf(callback_def, "  %s\n", im_directoroutattributes); +	if (!ignored_method) +	  Printf(director_delegate_definitions, "  %s\n", im_directoroutattributes); +      } + +      Printf(callback_def, "  private %s SwigDirectorMethod%s(", tm, overloaded_name); +      if (!ignored_method) { +	const String *csdirectordelegatemodifiers = Getattr(n, "feature:csdirectordelegatemodifiers"); +	String *modifiers = (csdirectordelegatemodifiers ? NewStringf("%s%s", csdirectordelegatemodifiers, Len(csdirectordelegatemodifiers) > 0 ? " " : "") : NewStringf("public ")); +	Printf(director_delegate_definitions, "  %sdelegate %s", modifiers, tm); +	Delete(modifiers); +      } +    } else { +      Swig_warning(WARN_CSHARP_TYPEMAP_CSTYPE_UNDEF, input_file, line_number, "No imtype typemap defined for %s\n", SwigType_str(returntype, 0)); +    } + +    if ((c_ret_type = Swig_typemap_lookup("ctype", n, "", 0))) { +      if (!is_void && !ignored_method) { +	String *jretval_decl = NewStringf("%s jresult", c_ret_type); +	Wrapper_add_localv(w, "jresult", jretval_decl, "= 0", NIL); +	Delete(jretval_decl); +      } +    } else { +      Swig_warning(WARN_CSHARP_TYPEMAP_CTYPE_UNDEF, input_file, line_number, "No ctype typemap defined for %s for use in %s::%s (skipping director method)\n",  +	  SwigType_str(returntype, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); +      output_director = false; +    } + +    Swig_director_parms_fixup(l); + +    /* Attach the standard typemaps */ +    Swig_typemap_attach_parms("out", l, 0); +    Swig_typemap_attach_parms("ctype", l, 0); +    Swig_typemap_attach_parms("imtype", l, 0); +    Swig_typemap_attach_parms("cstype", l, 0); +    Swig_typemap_attach_parms("directorin", l, w); +    Swig_typemap_attach_parms("csdirectorin", l, 0); +    Swig_typemap_attach_parms("directorargout", l, w); + +    /* Preamble code */ +    if (!ignored_method) +      Printf(w->code, "if (!swig_callback%s) {\n", overloaded_name); + +    if (!pure_virtual) { +      String *super_call = Swig_method_call(super, l); +      if (is_void) { +	Printf(w->code, "%s;\n", super_call); +	if (!ignored_method) +	  Printf(w->code, "return;\n"); +      } else { +	Printf(w->code, "return %s;\n", super_call); +      } +      Delete(super_call); +    } else { +      Printf(w->code, "Swig::DirectorPureVirtualException::raise(\"%s::%s\");\n", SwigType_namestr(c_classname), SwigType_namestr(name)); +      if (!is_void) +	Printf(w->code, "return %s;", qualified_return); +      else if (!ignored_method) +	Printf(w->code, "return;\n"); +    } + +    if (!ignored_method) +      Printf(w->code, "} else {\n"); + +    /* Go through argument list, convert from native to C# */ +    for (i = 0, p = l; p; ++i) { +      /* Is this superfluous? */ +      while (checkAttribute(p, "tmap:directorin:numinputs", "0")) { +	p = Getattr(p, "tmap:directorin:next"); +      } + +      SwigType *pt = Getattr(p, "type"); +      String *ln = makeParameterName(n, p, i, false); +      String *c_param_type = NULL; +      String *c_decl = NewString(""); +      String *arg = NewString(""); + +      Printf(arg, "j%s", ln); + +      /* And add to the upcall args */ +      if (i > 0) +	Printf(jupcall_args, ", "); +      Printf(jupcall_args, "%s", arg); + +      /* Get parameter's intermediary C type */ +      if ((c_param_type = Getattr(p, "tmap:ctype"))) { +	String *ctypeout = Getattr(p, "tmap:ctype:out");	// the type in the ctype typemap's out attribute overrides the type in the typemap +	if (ctypeout) +	  c_param_type = ctypeout; + +	/* Add to local variables */ +	Printf(c_decl, "%s %s", c_param_type, arg); +	if (!ignored_method) +	  Wrapper_add_localv(w, arg, c_decl, (!(SwigType_ispointer(pt) || SwigType_isreference(pt)) ? "" : "= 0"), NIL); + +	/* Add input marshalling code */ +	if ((tm = Getattr(p, "tmap:directorin"))) { + +	  Setattr(p, "emit:directorinput", arg); +	  Replaceall(tm, "$input", arg); +	  Replaceall(tm, "$owner", "0"); + +	  if (Len(tm)) +	    if (!ignored_method) +	      Printf(w->code, "%s\n", tm); + +	  /* Add C type to callback typedef */ +	  if (i > 0) +	    Printf(callback_typedef_parms, ", "); +	  Printf(callback_typedef_parms, "%s", c_param_type); + +	  /* Add parameter to the intermediate class code if generating the +	   * intermediate's upcall code */ +	  if ((tm = Getattr(p, "tmap:imtype"))) { + +	    String *imtypeout = Getattr(p, "tmap:imtype:out");	// the type in the imtype typemap's out attribute overrides the type in the typemap +	    if (imtypeout) +	      tm = imtypeout; +            const String *im_directorinattributes = Getattr(p, "tmap:imtype:directorinattributes"); + +	    String *din = Copy(Getattr(p, "tmap:csdirectorin")); + +	    if (din) { +	      Replaceall(din, "$module", module_class_name); +	      Replaceall(din, "$imclassname", imclass_name); +	      substituteClassname(pt, din); +	      Replaceall(din, "$iminput", ln); + +	      // pre and post attribute support +	      String *pre = Getattr(p, "tmap:csdirectorin:pre"); +	      if (pre) { +		substituteClassname(pt, pre); +		Replaceall(pre, "$iminput", ln); +		if (Len(pre_code) > 0) +		  Printf(pre_code, "\n"); +		Printv(pre_code, pre, NIL); +	      } +	      String *post = Getattr(p, "tmap:csdirectorin:post"); +	      if (post) { +		substituteClassname(pt, post); +		Replaceall(post, "$iminput", ln); +		if (Len(post_code) > 0) +		  Printf(post_code, "\n"); +		Printv(post_code, post, NIL); +	      } +	      String *terminator = Getattr(p, "tmap:csdirectorin:terminator"); +	      if (terminator) { +		substituteClassname(pt, terminator); +		Replaceall(terminator, "$iminput", ln); +		if (Len(terminator_code) > 0) +		Insert(terminator_code, 0, "\n"); +		Insert(terminator_code, 0, terminator); +	      } + +	      if (i > 0) { +		Printf(delegate_parms, ", "); +		Printf(proxy_method_types, ", "); +		Printf(imcall_args, ", "); +	      } +	      Printf(delegate_parms, "%s%s %s", im_directorinattributes ? im_directorinattributes : empty_string, tm, ln); + +	      if (Cmp(din, ln)) { +		Printv(imcall_args, din, NIL); +	      } else +		Printv(imcall_args, ln, NIL); + +	      /* Get the C# parameter type */ +	      if ((tm = Getattr(p, "tmap:cstype"))) { +		substituteClassname(pt, tm); +		int flags = DOH_REPLACE_FIRST | DOH_REPLACE_ID_BEGIN | DOH_REPLACE_NOCOMMENT; +		if (Replace(tm, "ref ", "", flags) || Replace(tm, "ref\t", "", flags)) { +		  Printf(proxy_method_types, "typeof(%s).MakeByRefType()", tm); +		} else if (Replace(tm, "out ", "", flags) || Replace(tm, "out\t", "", flags)) { +		  Printf(proxy_method_types, "typeof(%s).MakeByRefType()", tm); +		} else { +		  Printf(proxy_method_types, "typeof(%s)", tm); +		} +	      } else { +		Swig_warning(WARN_CSHARP_TYPEMAP_CSWTYPE_UNDEF, input_file, line_number, "No cstype typemap defined for %s\n", SwigType_str(pt, 0)); +	      } +	    } else { +	      Swig_warning(WARN_CSHARP_TYPEMAP_CSDIRECTORIN_UNDEF, input_file, line_number, "No csdirectorin typemap defined for %s for use in %s::%s (skipping director method)\n",  +		  SwigType_str(pt, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); +	      output_director = false; +	    } +	  } else { +	    Swig_warning(WARN_CSHARP_TYPEMAP_CSTYPE_UNDEF, input_file, line_number, "No imtype typemap defined for %s for use in %s::%s (skipping director method)\n",  +		SwigType_str(pt, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); +	    output_director = false; +	  } + +	  p = Getattr(p, "tmap:directorin:next"); + +	} else { +	  Swig_warning(WARN_CSHARP_TYPEMAP_CSDIRECTORIN_UNDEF, input_file, line_number, +		       "No or improper directorin typemap defined for argument %s for use in %s::%s (skipping director method)\n",  +		       SwigType_str(pt, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); +	  p = nextSibling(p); +	  output_director = false; +	} +      } else { +	Swig_warning(WARN_CSHARP_TYPEMAP_CTYPE_UNDEF, input_file, line_number, "No ctype typemap defined for %s for use in %s::%s (skipping director method)\n",  +	    SwigType_str(pt, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); +	output_director = false; +	p = nextSibling(p); +      } + +      Delete(ln); +      Delete(arg); +      Delete(c_decl); +    } + +    /* header declaration, start wrapper definition */ +    String *target; +    SwigType *rtype = Getattr(n, "conversion_operator") ? 0 : Getattr(n, "classDirectorMethods:type"); +    target = Swig_method_decl(rtype, decl, qualified_name, l, 0); +    Printf(w->def, "%s", target); +    Delete(qualified_name); +    Delete(target); +    target = Swig_method_decl(rtype, decl, name, l, 1); +    Printf(declaration, "    virtual %s", target); +    Delete(target); + +    // Add any exception specifications to the methods in the director class +    if (Getattr(n, "noexcept")) { +      Append(w->def, " noexcept"); +      Append(declaration, " noexcept"); +    } +    ParmList *throw_parm_list = NULL; +    if ((throw_parm_list = Getattr(n, "throws")) || Getattr(n, "throw")) { +      int gencomma = 0; + +      Append(w->def, " throw("); +      Append(declaration, " throw("); + +      if (throw_parm_list) +	Swig_typemap_attach_parms("throws", throw_parm_list, 0); +      for (p = throw_parm_list; p; p = nextSibling(p)) { +	if (Getattr(p, "tmap:throws")) { +	  if (gencomma++) { +	    Append(w->def, ", "); +	    Append(declaration, ", "); +	  } +	  Printf(w->def, "%s", SwigType_str(Getattr(p, "type"), 0)); +	  Printf(declaration, "%s", SwigType_str(Getattr(p, "type"), 0)); +	} +      } + +      Append(w->def, ")"); +      Append(declaration, ")"); +    } + +    Append(w->def, " {"); +    Append(declaration, ";\n"); + +    /* Finish off the inherited upcall's definition */ + +    Printf(callback_def, "%s)", delegate_parms); +    Printf(callback_def, " {\n"); + +    /* Emit the intermediate class's upcall to the actual class */ + +    String *upcall = NewStringf("%s(%s)", symname, imcall_args); + +    if ((tm = Swig_typemap_lookup("csdirectorout", n, "", 0))) { +      substituteClassname(returntype, tm); +      Replaceall(tm, "$cscall", upcall); +      if (!is_void) +	Insert(tm, 0, "return "); +      Replaceall(tm, "\n ", "\n   "); // add extra indentation to code in typemap + +      // pre and post attribute support +      bool is_pre_code = Len(pre_code) > 0; +      bool is_post_code = Len(post_code) > 0; +      bool is_terminator_code = Len(terminator_code) > 0; +      if (is_pre_code && is_post_code) +	Printf(callback_code, "%s\n    try {\n      %s;\n    } finally {\n%s\n    }\n", pre_code, tm, post_code); +      else if (is_pre_code) +	Printf(callback_code, "%s\n    %s;\n", pre_code, tm); +      else if (is_post_code) +	Printf(callback_code, "    try {\n      %s;\n    } finally {\n%s\n    }\n", tm, post_code); +      else +	Printf(callback_code, "    %s;\n", tm); +      if (is_terminator_code) +	Printv(callback_code, "\n", terminator_code, NIL); +    } + +    Printf(callback_code, "  }\n"); +    Delete(upcall); + +    if (!ignored_method) { +      if (!is_void) +	Printf(w->code, "jresult = (%s) ", c_ret_type); + +      Printf(w->code, "swig_callback%s(%s);\n", overloaded_name, jupcall_args); + +      if (!is_void) { +	String *jresult_str = NewString("jresult"); +	String *result_str = NewString("c_result"); + +	/* Copy jresult into c_result... */ +	if ((tm = Swig_typemap_lookup("directorout", n, result_str, w))) { +	  Replaceall(tm, "$input", jresult_str); +	  Replaceall(tm, "$result", result_str); +	  Printf(w->code, "%s\n", tm); +	} else { +	  Swig_warning(WARN_TYPEMAP_DIRECTOROUT_UNDEF, input_file, line_number, +		       "Unable to use return type %s used in %s::%s (skipping director method)\n",  +		       SwigType_str(returntype, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); +	  output_director = false; +	} + +	Delete(jresult_str); +	Delete(result_str); +      } + +      /* Marshal outputs */ +      for (p = l; p;) { +	if ((tm = Getattr(p, "tmap:directorargout"))) { +	  canThrow(n, "directorargout", p); +	  Replaceall(tm, "$result", "jresult"); +	  Replaceall(tm, "$input", Getattr(p, "emit:directorinput")); +	  Printv(w->code, tm, "\n", NIL); +	  p = Getattr(p, "tmap:directorargout:next"); +	} else { +	  p = nextSibling(p); +	} +      } + +      /* Terminate wrapper code */ +      Printf(w->code, "}\n"); +      if (!is_void) +	Printf(w->code, "return %s;", qualified_return); +    } + +    Printf(w->code, "}"); + +    // We expose virtual protected methods via an extra public inline method which makes a straight call to the wrapped class' method +    String *inline_extra_method = NewString(""); +    if (dirprot_mode() && !is_public(n) && !pure_virtual) { +      Printv(inline_extra_method, declaration, NIL); +      String *extra_method_name = NewStringf("%sSwigPublic", name); +      Replaceall(inline_extra_method, name, extra_method_name); +      Replaceall(inline_extra_method, ";\n", " {\n      "); +      if (!is_void) +	Printf(inline_extra_method, "return "); +      String *methodcall = Swig_method_call(super, l); +      Printv(inline_extra_method, methodcall, ";\n    }\n", NIL); +      Delete(methodcall); +      Delete(extra_method_name); +    } + +    /* emit the director method */ +    if (status == SWIG_OK && output_director) { +      if (!is_void) { +	Replaceall(w->code, "$null", qualified_return); +      } else { +	Replaceall(w->code, "$null", ""); +      } +      if (!ignored_method) +	Printv(director_delegate_callback, "\n", callback_def, callback_code, NIL); +      if (!Getattr(n, "defaultargs")) { +	Replaceall(w->code, "$symname", symname); +	Wrapper_print(w, f_directors); +	Printv(f_directors_h, declaration, NIL); +	Printv(f_directors_h, inline_extra_method, NIL); +      } +    } + +    if (!ignored_method) { +      /* Emit the actual upcall through */ +      UpcallData *udata = addUpcallMethod(imclass_dmethod, symname, decl, overloaded_name); +      String *methid = Getattr(udata, "class_methodidx"); +      Setattr(n, "upcalldata", udata); +      /* +      Printf(stdout, "setting upcalldata, nodeType: %s %s::%s %p\n", nodeType(n), classname, Getattr(n, "name"), n); +      */ + +      Printf(director_callback_typedefs, "    typedef %s (SWIGSTDCALL* SWIG_Callback%s_t)(", c_ret_type, methid); +      Printf(director_callback_typedefs, "%s);\n", callback_typedef_parms); +      Printf(director_callbacks, "    SWIG_Callback%s_t swig_callback%s;\n", methid, overloaded_name); + +      Printf(director_delegate_definitions, " SwigDelegate%s_%s(%s);\n", classname, methid, delegate_parms); +      Printf(director_delegate_instances, "  private SwigDelegate%s_%s swigDelegate%s;\n", classname, methid, methid); +      Printf(director_method_types, "  private static global::System.Type[] swigMethodTypes%s = new global::System.Type[] { %s };\n", methid, proxy_method_types); +      Printf(director_connect_parms, "SwigDirector%s%s delegate%s", classname, methid, methid); +    } + +    Delete(pre_code); +    Delete(post_code); +    Delete(terminator_code); +    Delete(qualified_return); +    Delete(declaration); +    Delete(callback_typedef_parms); +    Delete(delegate_parms); +    Delete(proxy_method_types); +    Delete(callback_def); +    Delete(callback_code); +    Delete(dirclassname); +    DelWrapper(w); + +    return status; +  } + +  /* ------------------------------------------------------------ +   * classDirectorConstructor() +   * ------------------------------------------------------------ */ + +  int classDirectorConstructor(Node *n) { +    Node *parent = parentNode(n); +    String *decl = Getattr(n, "decl"); +    String *supername = Swig_class_name(parent); +    String *dirclassname = directorClassName(parent); +    String *sub = NewString(""); +    Parm *p; +    ParmList *superparms = Getattr(n, "parms"); +    ParmList *parms; +    int argidx = 0; + +    /* Assign arguments to superclass's parameters, if not already done */ +    for (p = superparms; p; p = nextSibling(p)) { +      String *pname = Getattr(p, "name"); + +      if (!pname) { +	pname = NewStringf("arg%d", argidx++); +	Setattr(p, "name", pname); +      } +    } + +    // TODO: Is this copy needed? +    parms = CopyParmList(superparms); + +    if (!Getattr(n, "defaultargs")) { +      /* constructor */ +      { +	String *basetype = Getattr(parent, "classtype"); +	String *target = Swig_method_decl(0, decl, dirclassname, parms, 0); +	String *call = Swig_csuperclass_call(0, basetype, superparms); + +	Printf(f_directors, "%s::%s : %s, %s {\n", dirclassname, target, call, Getattr(parent, "director:ctor")); +	Printf(f_directors, "  swig_init_callbacks();\n"); +	Printf(f_directors, "}\n\n"); + +	Delete(target); +	Delete(call); +      } + +      /* constructor header */ +      { +	String *target = Swig_method_decl(0, decl, dirclassname, parms, 1); +	Printf(f_directors_h, "    %s;\n", target); +	Delete(target); +      } +    } + +    Delete(sub); +    Delete(supername); +    Delete(parms); +    Delete(dirclassname); +    return Language::classDirectorConstructor(n); +  } + +  /* ------------------------------------------------------------ +   * classDirectorDefaultConstructor() +   * ------------------------------------------------------------ */ + +  int classDirectorDefaultConstructor(Node *n) { +    String *dirclassname = directorClassName(n); +    String *classtype = SwigType_namestr(Getattr(n, "name")); +    Wrapper *w = NewWrapper(); + +    Printf(w->def, "%s::%s() : %s {", dirclassname, dirclassname, Getattr(n, "director:ctor")); +    Printf(w->code, "}\n"); +    Wrapper_print(w, f_directors); + +    Printf(f_directors_h, "    %s();\n", dirclassname); +    DelWrapper(w); +    Delete(classtype); +    Delete(dirclassname); +    return Language::classDirectorDefaultConstructor(n); +  } + + +  /* ------------------------------------------------------------ +   * classDirectorInit() +   * ------------------------------------------------------------ */ + +  int classDirectorInit(Node *n) { +    Delete(none_comparison); +    none_comparison = NewString("");	// not used + +    Delete(director_ctor_code); +    director_ctor_code = NewString("$director_new"); + +    directorDeclaration(n); + +    Printf(f_directors_h, "%s {\n", Getattr(n, "director:decl")); +    Printf(f_directors_h, "\npublic:\n"); + +    /* Keep track of the director methods for this class */ +    first_class_dmethod = curr_class_dmethod = n_dmethods; + +    director_callback_typedefs = NewString(""); +    director_callbacks = NewString(""); +    director_delegate_callback = NewString(""); +    director_delegate_definitions = NewString(""); +    director_delegate_instances = NewString(""); +    director_method_types = NewString(""); +    director_connect_parms = NewString(""); + +    return Language::classDirectorInit(n); +  } + +  int classDeclaration(Node *n) { +    String *old_director_callback_typedefs = director_callback_typedefs; +    String *old_director_callbacks = director_callbacks; +    String *old_director_delegate_callback = director_delegate_callback; +    String *old_director_delegate_definitions = director_delegate_definitions; +    String *old_director_delegate_instances = director_delegate_instances; +    String *old_director_method_types = director_method_types; +    String *old_director_connect_parms = director_connect_parms; + +    int ret = Language::classDeclaration(n); + +    // these variables are deleted in emitProxyClassDefAndCPPCasts, hence no Delete here +    director_callback_typedefs = old_director_callback_typedefs; +    director_callbacks = old_director_callbacks; +    director_delegate_callback = old_director_delegate_callback; +    director_delegate_definitions = old_director_delegate_definitions; +    director_delegate_instances = old_director_delegate_instances; +    director_method_types = old_director_method_types; +    director_connect_parms = old_director_connect_parms; + +    return ret; +  } + +  /* ---------------------------------------------------------------------- +   * classDirectorDestructor() +   * ---------------------------------------------------------------------- */ + +  int classDirectorDestructor(Node *n) { +    Node *current_class = getCurrentClass(); +    String *dirclassname = directorClassName(current_class); +    Wrapper *w = NewWrapper(); + +    if (Getattr(n, "noexcept")) { +      Printf(f_directors_h, "    virtual ~%s() noexcept;\n", dirclassname); +      Printf(w->def, "%s::~%s() noexcept {\n", dirclassname, dirclassname); +    } else if (Getattr(n, "throw")) { +      Printf(f_directors_h, "    virtual ~%s() throw();\n", dirclassname); +      Printf(w->def, "%s::~%s() throw() {\n", dirclassname, dirclassname); +    } else { +      Printf(f_directors_h, "    virtual ~%s();\n", dirclassname); +      Printf(w->def, "%s::~%s() {\n", dirclassname, dirclassname); +    } + +    Printv(w->code, "}\n", NIL); + +    Wrapper_print(w, f_directors); + +    DelWrapper(w); +    Delete(dirclassname); +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * classDirectorEnd() +   * ------------------------------------------------------------ */ + +  int classDirectorEnd(Node *n) { +    int i; +    String *dirclassname = directorClassName(n); + +    Wrapper *w = NewWrapper(); + +    if (Len(director_callback_typedefs) > 0) { +      Printf(f_directors_h, "\n%s", director_callback_typedefs); +    } + +    Printf(f_directors_h, "    void swig_connect_director("); + +    Printf(w->def, "void %s::swig_connect_director(", dirclassname); + +    for (i = first_class_dmethod; i < curr_class_dmethod; ++i) { +      UpcallData *udata = Getitem(dmethods_seq, i); +      String *methid = Getattr(udata, "class_methodidx"); +      String *overname = Getattr(udata, "overname"); + +      Printf(f_directors_h, "SWIG_Callback%s_t callback%s", methid, overname); +      Printf(w->def, "SWIG_Callback%s_t callback%s", methid, overname); +      Printf(w->code, "swig_callback%s = callback%s;\n", overname, overname); +      if (i != curr_class_dmethod - 1) { +	Printf(f_directors_h, ", "); +	Printf(w->def, ", "); +      } +    } + +    Printf(f_directors_h, ");\n"); +    Printf(w->def, ") {"); + + +    if (Len(director_callbacks) > 0) { +      Printf(f_directors_h, "\nprivate:\n%s", director_callbacks); +    } +    Printf(f_directors_h, "    void swig_init_callbacks();\n"); +    Printf(f_directors_h, "};\n\n"); +    Printf(w->code, "}\n\n"); + +    Printf(w->code, "void %s::swig_init_callbacks() {\n", dirclassname); +    for (i = first_class_dmethod; i < curr_class_dmethod; ++i) { +      UpcallData *udata = Getitem(dmethods_seq, i); +      String *overname = Getattr(udata, "overname"); +      Printf(w->code, "swig_callback%s = 0;\n", overname); +    } +    Printf(w->code, "}"); + +    Wrapper_print(w, f_directors); + +    DelWrapper(w); +    Delete(dirclassname); + +    return Language::classDirectorEnd(n); +  } + +  /* -------------------------------------------------------------------- +   * classDirectorDisown() +   * ------------------------------------------------------------------*/ +  virtual int classDirectorDisown(Node *n) { +    (void) n; +    return SWIG_OK; +  } + +  /*---------------------------------------------------------------------- +   * extraDirectorProtectedCPPMethodsRequired() +   *--------------------------------------------------------------------*/ + +  bool extraDirectorProtectedCPPMethodsRequired() const { +    return false; +  } + +  /*---------------------------------------------------------------------- +   * directorDeclaration() +   * +   * Generate the director class's declaration +   * e.g. "class SwigDirector_myclass : public myclass, public Swig::Director {" +   *--------------------------------------------------------------------*/ +  +  void directorDeclaration(Node *n) { + +    String *base = Getattr(n, "classtype"); +    String *class_ctor = NewString("Swig::Director()"); + +    String *dirclassname = directorClassName(n); +    String *declaration = Swig_class_declaration(n, dirclassname); + +    Printf(declaration, " : public %s, public Swig::Director", base); + +    // Stash stuff for later. +    Setattr(n, "director:decl", declaration); +    Setattr(n, "director:ctor", class_ctor); + +    Delete(dirclassname); +  } + +  /*---------------------------------------------------------------------- +   * nestedClassesSupport() +   *--------------------------------------------------------------------*/ + +  NestedClassSupport nestedClassesSupport() const { +    return NCS_Full; +  } +};				/* class CSHARP */ + +/* ----------------------------------------------------------------------------- + * swig_csharp()    - Instantiate module + * ----------------------------------------------------------------------------- */ + +static Language *new_swig_csharp() { +  return new CSHARP(); +} +extern "C" Language *swig_csharp(void) { +  return new_swig_csharp(); +} + +/* ----------------------------------------------------------------------------- + * Static member variables + * ----------------------------------------------------------------------------- */ + +const char *CSHARP::usage = "\ +C# Options (available with -csharp)\n\ +     -dllimport <dl> - Override DllImport attribute name to <dl>\n\ +     -namespace <nm> - Generate wrappers into C# namespace <nm>\n\ +     -noproxy        - Generate the low-level functional interface instead\n\ +                       of proxy classes\n\ +     -oldvarnames    - Old intermediary method names for variable wrappers\n\ +     -outfile <file> - Write all C# into a single <file> located in the output directory\n\ +\n"; diff --git a/contrib/tools/swig/Source/Modules/d.cxx b/contrib/tools/swig/Source/Modules/d.cxx new file mode 100644 index 00000000000..31f300f2ea8 --- /dev/null +++ b/contrib/tools/swig/Source/Modules/d.cxx @@ -0,0 +1,4649 @@ +/* ----------------------------------------------------------------------------- + * This file is part of SWIG, which is licensed as a whole under version 3 + * (or any later version) of the GNU General Public License. Some additional + * terms also apply to certain portions of SWIG. The full details of the SWIG + * license and copyrights can be found in the LICENSE and COPYRIGHT files + * included with the SWIG source code as distributed by the SWIG developers + * and at https://www.swig.org/legal.html. + * + * d.cxx + * + * D language module for SWIG. + * ----------------------------------------------------------------------------- */ + +#include "swigmod.h" +#include "cparse.h" +#include <ctype.h> + +// Hash type used for storing information about director callbacks for a class. +typedef DOH UpcallData; + +class D : public Language { +  static const char *usage; +  const String *empty_string; +  const String *public_string; +  const String *protected_string; + +  /* +   * Files and file sections containing C/C++ code. +   */ +  File *f_begin; +  File *f_runtime; +  File *f_runtime_h; +  File *f_header; +  File *f_wrappers; +  File *f_init; +  File *f_directors; +  File *f_directors_h; +  List *filenames_list; + +  /* +   * Command line-set modes of operation. +   */ +  // Whether a single proxy D module is generated or classes and enums are +  // written to their own files. +  bool split_proxy_dmodule; + +  // The major D version targeted (currently 1 or 2). +  unsigned short d_version; + +  /* +   * State variables which indicate what is being wrapped at the moment. +   * This is probably not the most elegant way of handling state, but it has +   * proven to work in the C# and Java modules. +   */ +  // Indicates if wrapping a native function. +  bool native_function_flag; + +  // Indicates if wrapping a static functions or member variables +  bool static_flag; + +  // Indicates if wrapping a nonstatic member variable +  bool variable_wrapper_flag; + +  // Indicates if wrapping a member variable/enum/const. +  bool wrapping_member_flag; + +  // Indicates if wrapping a global variable. +  bool global_variable_flag; + +  // Name of a variable being wrapped. +  String *variable_name; + +  /* +   * Variables temporarily holding the generated C++ code. +   */ +  // C++ code for the generated wrapper functions for casts up the C++ +  // for inheritance hierarchies. +  String *upcasts_code; + +  // Function pointer typedefs for handling director callbacks on the C++ side. +  String *director_callback_typedefs; + +  // Variables for storing the function pointers to the director callbacks on +  // the C++ side. +  String *director_callback_pointers; + +  /* +   * Names of generated D entities. +   */ +  // The name of the D module containing the interface to the C wrapper. +  String *im_dmodule_name; + +  // The fully qualified name of the wrap D module (package name included). +  String *im_dmodule_fq_name; + +  // The name of the proxy module which exposes the (SWIG) module contents as a +  // D module. +  String *proxy_dmodule_name; + +  // The fully qualified name of the proxy D module. +  String *proxy_dmodule_fq_name; + +  // Optional: Package the D modules are placed in (set via the -package +  // command line option). +  String *package; + +  // The directory the generated D module files are written to. Is constructed +  // from the package path if a target package is set, points to the general +  // output directory otherwise. +  String *dmodule_directory; + +  // The name of the library which contains the C wrapper (used when generating +  // the dynamic library loader). Can be overridden via the -wrapperlibrary +  // command line flag. +  String *wrap_library_name; + +  /* +   * Variables temporarily holding the generated D code. +   */ +  // Import statements written to the intermediary D module header set via +  // %pragma(d) imdmoduleimports. +  String *im_dmodule_imports; + +  // The code for the intermediary D module body. +  String *im_dmodule_code; + +  // Import statements for all proxy modules (the main proxy module and, if in +  // split proxy module mode, the proxy class modules) from +  // %pragma(d) globalproxyimports. +  String *global_proxy_imports; + +  // The D code for the main proxy modules. nspace_proxy_dmodules is a hash from +  // the namespace name as key to an {"imports", "code"}. If the nspace feature +  // is not active, only proxy_dmodule_imports and proxy_dmodule_code are used, +  // which contain the code for the root proxy module. +  // +  // These variables should not be accessed directly but rather via the +  // proxy{Imports, Code}Buffer)() helper functions which return the right +  // buffer for a given namespace. If not in split proxy mode, they contain the +  // whole proxy code. +  String *proxy_dmodule_imports; +  String *proxy_dmodule_code; +  Hash *nspace_proxy_dmodules; + +  // The D code generated for the currently processed enum. +  String *proxy_enum_code; + +  /* +   * D data for the current proxy class. +   * +   * These strings are mainly used to temporarily accumulate code from the +   * various member handling functions while a single class is processed and are +   * no longer relevant once that class has been finished, i.e. after +   * classHandler() has returned. +   */ +  // The unqualified name of the current proxy class. +  String *proxy_class_name; + +  // The name of the current proxy class, qualified with the name of the +  // namespace it is in, if any. +  String *proxy_class_qname; + +  // The import directives for the current proxy class. They are written to the +  // same D module the proxy class is written to. +  String *proxy_class_imports; + +  // Code for enumerations nested in the current proxy class. Is emitted earlier +  // than the rest of the body to work around forward referencing-issues. +  String *proxy_class_enums_code; + +  // The generated D code making up the body of the current proxy class. +  String *proxy_class_body_code; + +  // D code which is emitted right after the proxy class. +  String *proxy_class_epilogue_code; + +  // The full code for the current proxy class, including the epilogue. +  String* proxy_class_code; + +  // Contains a D call to the function wrapping C++ the destructor of the +  // current class (if there is a public C++ destructor). +  String *destructor_call; + +  // D code for the director callbacks generated for the current class. +  String *director_dcallbacks_code; + +  /* +   * Code for dynamically loading the wrapper library on the D side. +   */ +  // D code which is inserted into the im D module if dynamic linking is used. +  String *wrapper_loader_code; + +  // The D code to bind a function pointer to a library symbol. +  String *wrapper_loader_bind_command; + +  // The cumulated binding commands binding all the functions declared in the +  // intermediary D module to the C/C++ library symbols. +  String *wrapper_loader_bind_code; + +  /* +   * Director data. +   */ +  List *dmethods_seq; +  Hash *dmethods_table; +  int n_dmethods; +  int first_class_dmethod; +  int curr_class_dmethod; + +  /* +   * SWIG types data. +   */ +  // Collects information about encountered types SWIG does not know about (e.g. +  // incomplete types). This is used later to generate type wrapper proxy +  // classes for the unknown types. +  Hash *unknown_types; + + +public: +  /* --------------------------------------------------------------------------- +   * D::D() +   * --------------------------------------------------------------------------- */ +   D():empty_string(NewString("")), +      public_string(NewString("public")), +      protected_string(NewString("protected")), +      f_begin(NULL), +      f_runtime(NULL), +      f_runtime_h(NULL), +      f_header(NULL), +      f_wrappers(NULL), +      f_init(NULL), +      f_directors(NULL), +      f_directors_h(NULL), +      filenames_list(NULL), +      split_proxy_dmodule(false), +      d_version(1), +      native_function_flag(false), +      static_flag(false), +      variable_wrapper_flag(false), +      wrapping_member_flag(false), +      global_variable_flag(false), +      variable_name(NULL), +      upcasts_code(NULL), +      director_callback_typedefs(NULL), +      director_callback_pointers(NULL), +      im_dmodule_name(NULL), +      im_dmodule_fq_name(NULL), +      proxy_dmodule_name(NULL), +      proxy_dmodule_fq_name(NULL), +      package(NULL), +      dmodule_directory(NULL), +      wrap_library_name(NULL), +      im_dmodule_imports(NULL), +      im_dmodule_code(NULL), +      global_proxy_imports(NULL), +      proxy_dmodule_imports(NULL), +      proxy_dmodule_code(NULL), +      nspace_proxy_dmodules(NULL), +      proxy_enum_code(NULL), +      proxy_class_name(NULL), +      proxy_class_qname(NULL), +      proxy_class_imports(NULL), +      proxy_class_enums_code(NULL), +      proxy_class_body_code(NULL), +      proxy_class_epilogue_code(NULL), +      proxy_class_code(NULL), +      destructor_call(NULL), +      director_dcallbacks_code(NULL), +      wrapper_loader_code(NULL), +      wrapper_loader_bind_command(NULL), +      wrapper_loader_bind_code(NULL), +      dmethods_seq(NULL), +      dmethods_table(NULL), +      n_dmethods(0), +      first_class_dmethod(0), +      curr_class_dmethod(0), +      unknown_types(NULL) { + +    // For now, multiple inheritance with directors is not possible. It should be +    // easy to implement though. +    director_multiple_inheritance = 0; +    director_language = 1; + +    // Not used: +    Delete(none_comparison); +    none_comparison = NewString(""); +  } + +  /* --------------------------------------------------------------------------- +   * D::main() +   * --------------------------------------------------------------------------- */ +  virtual void main(int argc, char *argv[]) { +    SWIG_library_directory("d"); + +    // Look for certain command line options +    for (int i = 1; i < argc; i++) { +      if (argv[i]) { +	if ((strcmp(argv[i], "-d2") == 0)) { +      	  Swig_mark_arg(i); +      	  d_version = 2; +      	} else if (strcmp(argv[i], "-wrapperlibrary") == 0) { +	  if (argv[i + 1]) { +	    wrap_library_name = NewString(""); +	    Printf(wrap_library_name, argv[i + 1]); +	    Swig_mark_arg(i); +	    Swig_mark_arg(i + 1); +	    i++; +	  } else { +	    Swig_arg_error(); +	  } +	} else if (strcmp(argv[i], "-package") == 0) { +	  if (argv[i + 1]) { +	    package = NewString(""); +	    Printf(package, argv[i + 1]); +	    Swig_mark_arg(i); +	    Swig_mark_arg(i + 1); +	    i++; +	  } else { +	    Swig_arg_error(); +	  } +	} else if ((strcmp(argv[i], "-splitproxy") == 0)) { +	  Swig_mark_arg(i); +	  split_proxy_dmodule = true; +	} else if (strcmp(argv[i], "-help") == 0) { +	  Printf(stdout, "%s\n", usage); +	} +      } +    } + +    // Add a symbol to the parser for conditional compilation +    Preprocessor_define("SWIGD 1", 0); + +    // Also make the target D version available as preprocessor symbol for +    // use in our library files. +    String *version_define = NewStringf("SWIG_D_VERSION %u", d_version); +    Preprocessor_define(version_define, 0); +    Delete(version_define); + +    // Add typemap definitions +    SWIG_typemap_lang("d"); +    SWIG_config_file("d.swg"); + +    allow_overloading(); +  } + +  /* --------------------------------------------------------------------------- +   * D::top() +   * --------------------------------------------------------------------------- */ +  virtual int top(Node *n) { +    // Get any options set in the module directive +    Node *optionsnode = Getattr(Getattr(n, "module"), "options"); + +    if (optionsnode) { +      if (Getattr(optionsnode, "imdmodulename")) { +	im_dmodule_name = Copy(Getattr(optionsnode, "imdmodulename")); +      } + +      if (Getattr(optionsnode, "directors")) { +	// Check if directors are enabled for this module. Note: This is a +	// "master switch", if it is not set, not director code will be emitted +	// at all. %feature("director") statements are also required to enable +	// directors for individual classes or methods. +	// +	// Use the »directors« attributte of the %module directive to enable +	// director generation (e.g. »%module(directors="1") modulename«). +	allow_directors(); +      } + +      if (Getattr(optionsnode, "dirprot")) { +	allow_dirprot(); +      } + +      allow_allprotected(GetFlag(optionsnode, "allprotected")); +    } + +    /* Initialize all of the output files */ +    String *outfile = Getattr(n, "outfile"); +    String *outfile_h = Getattr(n, "outfile_h"); + +    if (!outfile) { +      Printf(stderr, "Unable to determine outfile\n"); +      Exit(EXIT_FAILURE); +    } + +    f_begin = NewFile(outfile, "w", SWIG_output_files()); +    if (!f_begin) { +      FileErrorDisplay(outfile); +      Exit(EXIT_FAILURE); +    } + +    if (directorsEnabled()) { +      if (!outfile_h) { +	Printf(stderr, "Unable to determine outfile_h\n"); +	Exit(EXIT_FAILURE); +      } +      f_runtime_h = NewFile(outfile_h, "w", SWIG_output_files()); +      if (!f_runtime_h) { +	FileErrorDisplay(outfile_h); +	Exit(EXIT_FAILURE); +      } +    } + +    f_runtime = NewString(""); +    f_init = NewString(""); +    f_header = NewString(""); +    f_wrappers = NewString(""); +    f_directors_h = NewString(""); +    f_directors = NewString(""); + +    /* Register file targets with the SWIG file handler */ +    Swig_register_filebyname("header", f_header); +    Swig_register_filebyname("wrapper", f_wrappers); +    Swig_register_filebyname("begin", f_begin); +    Swig_register_filebyname("runtime", f_runtime); +    Swig_register_filebyname("init", f_init); +    Swig_register_filebyname("director", f_directors); +    Swig_register_filebyname("director_h", f_directors_h); + +    unknown_types = NewHash(); +    filenames_list = NewList(); + +    // Make the package name and the resulting module output path. +    if (package) { +      // Append a dot so we can prepend the package variable directly to the +      // module names in the rest of the code. +      Printv(package, ".", NIL); +    } else { +      // Write the generated D modules to the »root« package by default. +      package = NewString(""); +    } + +    dmodule_directory = Copy(SWIG_output_directory()); +    if (Len(package) > 0) { +      String *package_directory = Copy(package); +      Replaceall(package_directory, ".", SWIG_FILE_DELIMITER); +      Printv(dmodule_directory, package_directory, NIL); +      Delete(package_directory); +    } + +    // Make the wrap and proxy D module names. +    // The wrap module name can be set in the module directive. +    if (!im_dmodule_name) { +      im_dmodule_name = NewStringf("%s_im", Getattr(n, "name")); +    } +    im_dmodule_fq_name = NewStringf("%s%s", package, im_dmodule_name); +    proxy_dmodule_name = Copy(Getattr(n, "name")); +    proxy_dmodule_fq_name = NewStringf("%s%s", package, proxy_dmodule_name); + +    im_dmodule_code = NewString(""); +    proxy_class_imports = NewString(""); +    proxy_class_enums_code = NewString(""); +    proxy_class_body_code = NewString(""); +    proxy_class_epilogue_code = NewString(""); +    proxy_class_code = NewString(""); +    destructor_call = NewString(""); +    proxy_dmodule_code = NewString(""); +    proxy_dmodule_imports = NewString(""); +    nspace_proxy_dmodules = NewHash(); +    im_dmodule_imports = NewString(""); +    upcasts_code = NewString(""); +    global_proxy_imports = NewString(""); +    wrapper_loader_code = NewString(""); +    wrapper_loader_bind_command = NewString(""); +    wrapper_loader_bind_code = NewString(""); +    dmethods_seq = NewList(); +    dmethods_table = NewHash(); +    n_dmethods = 0; + +    // By default, expect the dynamically loaded wrapper library to be named +    // [lib]<module>_wrap[.so/.dll]. +    if (!wrap_library_name) +      wrap_library_name = NewStringf("%s_wrap", Getattr(n, "name")); + +    Swig_banner(f_begin); + +    Swig_obligatory_macros(f_runtime, "D"); + +    if (directorsEnabled()) { +      Printf(f_runtime, "#define SWIG_DIRECTORS\n"); + +      /* Emit initial director header and director code: */ +      Swig_banner(f_directors_h); +      Printf(f_directors_h, "\n"); +      Printf(f_directors_h, "#ifndef SWIG_%s_WRAP_H_\n", proxy_dmodule_name); +      Printf(f_directors_h, "#define SWIG_%s_WRAP_H_\n\n", proxy_dmodule_name); + +      Printf(f_directors, "\n\n"); +      Printf(f_directors, "/* ---------------------------------------------------\n"); +      Printf(f_directors, " * C++ director class methods\n"); +      Printf(f_directors, " * --------------------------------------------------- */\n\n"); +      if (outfile_h) { +	String *filename = Swig_file_filename(outfile_h); +	Printf(f_directors, "#include \"%s\"\n\n", filename); +	Delete(filename); +      } +    } + +    Printf(f_runtime, "\n"); + +    Swig_name_register("wrapper", "D_%f"); + +    Printf(f_wrappers, "\n#ifdef __cplusplus\n"); +    Printf(f_wrappers, "extern \"C\" {\n"); +    Printf(f_wrappers, "#endif\n\n"); + +    // Emit all the wrapper code. +    Language::top(n); + +    if (directorsEnabled()) { +      // Insert director runtime into the f_runtime file (before %header section). +      Swig_insert_file("director_common.swg", f_runtime); +      Swig_insert_file("director.swg", f_runtime); +    } + +    // Generate the wrap D module. +    // TODO: Add support for »static« linking. +    { +      String *filen = NewStringf("%s%s.d", dmodule_directory, im_dmodule_name); +      File *im_d_file = NewFile(filen, "w", SWIG_output_files()); +      if (!im_d_file) { +	FileErrorDisplay(filen); +	Exit(EXIT_FAILURE); +      } +      Append(filenames_list, Copy(filen)); +      Delete(filen); +      filen = NULL; + +      // Start writing out the intermediary class file. +      emitBanner(im_d_file); + +      Printf(im_d_file, "module %s;\n", im_dmodule_fq_name); + +      Printv(im_d_file, im_dmodule_imports, "\n", NIL); + +      Replaceall(wrapper_loader_code, "$wraplibrary", wrap_library_name); +      Replaceall(wrapper_loader_code, "$wrapperloaderbindcode", wrapper_loader_bind_code); +      Replaceall(wrapper_loader_code, "$module", proxy_dmodule_name); +      Printf(im_d_file, "%s\n", wrapper_loader_code); + +      // Add the wrapper function declarations. +      replaceModuleVariables(im_dmodule_code); +      Printv(im_d_file, im_dmodule_code, NIL); + +      Delete(im_d_file); +    } + +    // Generate the main D proxy module. +    { +      String *filen = NewStringf("%s%s.d", dmodule_directory, proxy_dmodule_name); +      File *proxy_d_file = NewFile(filen, "w", SWIG_output_files()); +      if (!proxy_d_file) { +	FileErrorDisplay(filen); +	Exit(EXIT_FAILURE); +      } +      Append(filenames_list, Copy(filen)); +      Delete(filen); +      filen = NULL; + +      emitBanner(proxy_d_file); + +      Printf(proxy_d_file, "module %s;\n", proxy_dmodule_fq_name); +      Printf(proxy_d_file, "\nstatic import %s;\n", im_dmodule_fq_name); +      Printv(proxy_d_file, global_proxy_imports, NIL); +      Printv(proxy_d_file, proxy_dmodule_imports, NIL); +      Printv(proxy_d_file, "\n", NIL); + +      // Write a D type wrapper class for each SWIG type to the proxy module code. +      for (Iterator swig_type = First(unknown_types); swig_type.key; swig_type = Next(swig_type)) { +	writeTypeWrapperClass(swig_type.key, swig_type.item); +      } + +      // Add the proxy functions (and classes, if they are not written to a separate file). +      replaceModuleVariables(proxy_dmodule_code); +      Printv(proxy_d_file, proxy_dmodule_code, NIL); + +      Delete(proxy_d_file); +    } + +    // Generate the additional proxy modules for nspace support. +    for (Iterator it = First(nspace_proxy_dmodules); it.key; it = Next(it)) { +      String *module_name = createLastNamespaceName(it.key); + +      String *filename = NewStringf("%s%s.d", outputDirectory(it.key), module_name); +      File *file = NewFile(filename, "w", SWIG_output_files()); +      if (!file) { +	FileErrorDisplay(filename); +	Exit(EXIT_FAILURE); +      } +      Delete(filename); + +      emitBanner(file); + +      Printf(file, "module %s%s.%s;\n", package, it.key, module_name); +      Printf(file, "\nstatic import %s;\n", im_dmodule_fq_name); +      Printv(file, global_proxy_imports, NIL); +      Printv(file, Getattr(it.item, "imports"), NIL); +      Printv(file, "\n", NIL); + +      String *code = Getattr(it.item, "code"); +      replaceModuleVariables(code); +      Printv(file, code, NIL); + +      Delete(file); +      Delete(module_name); +    } + +    if (upcasts_code) +      Printv(f_wrappers, upcasts_code, NIL); + +    Printf(f_wrappers, "#ifdef __cplusplus\n"); +    Printf(f_wrappers, "}\n"); +    Printf(f_wrappers, "#endif\n"); + +    // Check for overwriting file problems on filesystems that are case insensitive +    Iterator it1; +    Iterator it2; +    for (it1 = First(filenames_list); it1.item; it1 = Next(it1)) { +      String *item1_lower = Swig_string_lower(it1.item); +      for (it2 = Next(it1); it2.item; it2 = Next(it2)) { +	String *item2_lower = Swig_string_lower(it2.item); +	if (it1.item && it2.item) { +	  if (Strcmp(item1_lower, item2_lower) == 0) { +	    Swig_warning(WARN_LANG_PORTABILITY_FILENAME, input_file, line_number, +			 "Portability warning: File %s will be overwritten by %s on case insensitive filesystems such as " +			 "Windows' FAT32 and NTFS unless the class/module name is renamed\n", it1.item, it2.item); +	  } +	} +	Delete(item2_lower); +      } +      Delete(item1_lower); +    } + +    Delete(unknown_types); +    unknown_types = NULL; +    Delete(filenames_list); +    filenames_list = NULL; +    Delete(im_dmodule_name); +    im_dmodule_name = NULL; +    Delete(im_dmodule_fq_name); +    im_dmodule_fq_name = NULL; +    Delete(im_dmodule_code); +    im_dmodule_code = NULL; +    Delete(proxy_class_imports); +    proxy_class_imports = NULL; +    Delete(proxy_class_enums_code); +    proxy_class_enums_code = NULL; +    Delete(proxy_class_body_code); +    proxy_class_body_code = NULL; +    Delete(proxy_class_epilogue_code); +    proxy_class_epilogue_code = NULL; +    Delete(proxy_class_code); +    proxy_class_code = NULL; +    Delete(destructor_call); +    destructor_call = NULL; +    Delete(proxy_dmodule_name); +    proxy_dmodule_name = NULL; +    Delete(proxy_dmodule_fq_name); +    proxy_dmodule_fq_name = NULL; +    Delete(proxy_dmodule_code); +    proxy_dmodule_code = NULL; +    Delete(proxy_dmodule_imports); +    proxy_dmodule_imports = NULL; +    Delete(nspace_proxy_dmodules); +    nspace_proxy_dmodules = NULL; +    Delete(im_dmodule_imports); +    im_dmodule_imports = NULL; +    Delete(upcasts_code); +    upcasts_code = NULL; +    Delete(global_proxy_imports); +    global_proxy_imports = NULL; +    Delete(wrapper_loader_code); +    wrapper_loader_code = NULL; +    Delete(wrapper_loader_bind_code); +    wrapper_loader_bind_code = NULL; +    Delete(wrapper_loader_bind_command); +    wrapper_loader_bind_command = NULL; +    Delete(dmethods_seq); +    dmethods_seq = NULL; +    Delete(dmethods_table); +    dmethods_table = NULL; +    Delete(package); +    package = NULL; +    Delete(dmodule_directory); +    dmodule_directory = NULL; +    n_dmethods = 0; + +    // Merge all the generated C/C++ code and close the output files. +    Dump(f_runtime, f_begin); +    Dump(f_header, f_begin); + +    if (directorsEnabled()) { +      Dump(f_directors, f_begin); +      Dump(f_directors_h, f_runtime_h); + +      Printf(f_runtime_h, "\n"); +      Printf(f_runtime_h, "#endif\n"); + +      Delete(f_runtime_h); +      f_runtime_h = NULL; +      Delete(f_directors); +      f_directors = NULL; +      Delete(f_directors_h); +      f_directors_h = NULL; +    } + +    Dump(f_wrappers, f_begin); +    Wrapper_pretty_print(f_init, f_begin); +    Delete(f_header); +    Delete(f_wrappers); +    Delete(f_init); +    Delete(f_runtime); +    Delete(f_begin); + +    return SWIG_OK; +  } + +  /* --------------------------------------------------------------------------- +   * D::insertDirective() +   * --------------------------------------------------------------------------- */ +  virtual int insertDirective(Node *n) { +    int ret = SWIG_OK; +    String *code = Getattr(n, "code"); +    String *section = Getattr(n, "section"); +    replaceModuleVariables(code); + +    if (!ImportMode && (Cmp(section, "proxycode") == 0)) { +      if (proxy_class_body_code) { +	Swig_typemap_replace_embedded_typemap(code, n); +	Printv(proxy_class_body_code, code, NIL); +      } +    } else { +      ret = Language::insertDirective(n); +    } +    return ret; +  } + +  /* --------------------------------------------------------------------------- +   * D::pragmaDirective() +   * +   * Valid Pragmas: +   * imdmodulecode      - text (D code) is copied verbatim to the wrap module +   * imdmoduleimports   - import statements for the im D module +   * +   * proxydmodulecode     - text (D code) is copied verbatim to the proxy module +   *                        (the main proxy module if in split proxy mode). +   * globalproxyimports   - import statements inserted into _all_ proxy modules. +   * +   * wrapperloadercode    - D code for loading the wrapper library (is copied to +   *                        the im D module). +   * wrapperloaderbindcommand - D code for binding a symbol from the wrapper +   *                        library to the declaration in the im D module. +   * --------------------------------------------------------------------------- */ +  virtual int pragmaDirective(Node *n) { +    if (!ImportMode) { +      String *lang = Getattr(n, "lang"); +      String *code = Getattr(n, "name"); +      String *value = Getattr(n, "value"); + +      if (Strcmp(lang, "d") == 0) { +	String *strvalue = NewString(value); +	Replaceall(strvalue, "\\\"", "\""); + +	if (Strcmp(code, "imdmodulecode") == 0) { +	  Printf(im_dmodule_code, "%s\n", strvalue); +	} else if (Strcmp(code, "imdmoduleimports") == 0) { +	  replaceImportTypeMacros(strvalue); +	  Chop(strvalue); +	  Printf(im_dmodule_imports, "%s\n", strvalue); +	} else if (Strcmp(code, "proxydmodulecode") == 0) { +	  Printf(proxyCodeBuffer(0), "%s\n", strvalue); +	} else if (Strcmp(code, "globalproxyimports") == 0) { +	  replaceImportTypeMacros(strvalue); +	  Chop(strvalue); +	  Printf(global_proxy_imports, "%s\n", strvalue); +	} else if (Strcmp(code, "wrapperloadercode") == 0) { +	  Delete(wrapper_loader_code); +	  wrapper_loader_code = Copy(strvalue); +	} else if (Strcmp(code, "wrapperloaderbindcommand") == 0) { +	  Delete(wrapper_loader_bind_command); +	  wrapper_loader_bind_command = Copy(strvalue); +	} else { +	  Swig_error(input_file, line_number, "Unrecognized pragma.\n"); +	} +	Delete(strvalue); +      } +    } +    return Language::pragmaDirective(n); +  } + +  /* --------------------------------------------------------------------------- +   * D::enumDeclaration() +   * +   * Wraps C/C++ enums as D enums. +   * --------------------------------------------------------------------------- */ +  virtual int enumDeclaration(Node *n) { +    if (ImportMode) +      return SWIG_OK; + +    if (getCurrentClass() && (cplus_mode != PUBLIC)) +      return SWIG_NOWRAP; + +    proxy_enum_code = NewString(""); +    String *symname = Getattr(n, "sym:name"); +    String *typemap_lookup_type = Getattr(n, "name"); + +    // Emit the enum declaration. +    if (typemap_lookup_type) { +      const String *enummodifiers = lookupCodeTypemap(n, "dclassmodifiers", typemap_lookup_type, WARN_D_TYPEMAP_CLASSMOD_UNDEF); +      Printv(proxy_enum_code, "\n", enummodifiers, " ", symname, " {\n", NIL); +    } else { +      // Handle anonymous enums. +      Printv(proxy_enum_code, "\nenum {\n", NIL); +    } + +    // Emit each enum item. +    Language::enumDeclaration(n); + +    if (GetFlag(n, "nonempty")) { +      // Finish the enum. +      if (typemap_lookup_type) { +	Printv(proxy_enum_code, +	  lookupCodeTypemap(n, "dcode", typemap_lookup_type, WARN_NONE), // Extra D code +	  "\n}\n", NIL); +      } else { +	// Handle anonymous enums. +	Printv(proxy_enum_code, "\n}\n", NIL); +      } +      Replaceall(proxy_enum_code, "$dclassname", symname); +    } else { +      // D enum declarations must have at least one member to be legal, so emit +      // an alias to int instead (their ctype/imtype is always int). +      Delete(proxy_enum_code); +      proxy_enum_code = NewStringf("\nalias int %s;\n", symname); +    } + +    const String* imports = +      lookupCodeTypemap(n, "dimports", typemap_lookup_type, WARN_NONE); +    String* imports_trimmed; +    if (Len(imports) > 0) { +      imports_trimmed = Copy(imports); +      Chop(imports_trimmed); +      replaceImportTypeMacros(imports_trimmed); +      Printv(imports_trimmed, "\n", NIL); +    } else { +      imports_trimmed = NewString(""); +    } + +    if (is_wrapping_class()) { +      // Enums defined within the C++ class are written into the proxy +      // class. +      Printv(proxy_class_imports, imports_trimmed, NIL); +      Printv(proxy_class_enums_code, proxy_enum_code, NIL); +    } else { +      // Write non-anonymous enums to their own file if in split proxy module +      // mode. +      if (split_proxy_dmodule && typemap_lookup_type) { +	assertClassNameValidity(proxy_class_name); + +	String *nspace = Getattr(n, "sym:nspace"); +	String *output_directory = outputDirectory(nspace); +	String *filename = NewStringf("%s%s.d", output_directory, symname); +	Delete(output_directory); + +	File *class_file = NewFile(filename, "w", SWIG_output_files()); +	if (!class_file) { +	  FileErrorDisplay(filename); +	  Exit(EXIT_FAILURE); +	} +	Append(filenames_list, Copy(filename)); +	Delete(filename); + +	emitBanner(class_file); +	if (nspace) { +	  Printf(class_file, "module %s%s.%s;\n", package, nspace, symname); +	} else { +	  Printf(class_file, "module %s%s;\n", package, symname); +	} +	Printv(class_file, imports_trimmed, NIL); + +	Printv(class_file, proxy_enum_code, NIL); + +	Delete(class_file); +      } else { +	String *nspace = Getattr(n, "sym:nspace"); +	Printv(proxyImportsBuffer(nspace), imports, NIL); +	Printv(proxyCodeBuffer(nspace), proxy_enum_code, NIL); +      } +    } + +    Delete(imports_trimmed); + +    Delete(proxy_enum_code); +    proxy_enum_code = NULL; +    return SWIG_OK; +  } + +  /* --------------------------------------------------------------------------- +   * D::enumvalueDeclaration() +   * --------------------------------------------------------------------------- */ +  virtual int enumvalueDeclaration(Node *n) { +    if (getCurrentClass() && (cplus_mode != PUBLIC)) +      return SWIG_NOWRAP; + +    Swig_require("enumvalueDeclaration", n, "*name", "?value", NIL); +    String *value = Getattr(n, "value"); +    String *name = Getattr(n, "name"); +    Node *parent = parentNode(n); +    String *tmpValue; + +    // Strange hack from parent method. +    // RESEARCH: What is this doing? +    if (value) +      tmpValue = NewString(value); +    else +      tmpValue = NewString(name); +    // Note that this is used in enumValue() amongst other places +    Setattr(n, "value", tmpValue); + +    // Deal with enum values that are not int +    int swigtype = SwigType_type(Getattr(n, "type")); +    if (swigtype == T_BOOL) { +      const char *val = Equal(Getattr(n, "enumvalue"), "true") ? "1" : "0"; +      Setattr(n, "enumvalue", val); +    } else if (swigtype == T_CHAR) { +      String *val = NewStringf("'%(escape)s'", Getattr(n, "enumvalue")); +      Setattr(n, "enumvalue", val); +      Delete(val); +    } + +    // Emit the enum item. +    { +      if (!GetFlag(n, "firstenumitem")) +	Printf(proxy_enum_code, ",\n"); + +      Printf(proxy_enum_code, "  %s", Getattr(n, "sym:name")); + +      // Check for the %dconstvalue feature +      String *value = Getattr(n, "feature:d:constvalue"); + +      // Note that in D, enum values must be compile-time constants. Thus, +      // %dmanifestconst(0) (getting the enum values at runtime) is not supported. +      value = value ? value : Getattr(n, "enumvalue"); +      if (value) { +	Printf(proxy_enum_code, " = %s", value); +      } + +      // Keep track that the currently processed enum has at least one value. +      SetFlag(parent, "nonempty"); +    } + +    Delete(tmpValue); +    Swig_restore(n); +    return SWIG_OK; +  } + +  /* --------------------------------------------------------------------------- +   * D::memberfunctionHandler() +   * --------------------------------------------------------------------------- */ +  virtual int memberfunctionHandler(Node *n) { +    Language::memberfunctionHandler(n); + +    String *overloaded_name = getOverloadedName(n); +    String *intermediary_function_name = +      Swig_name_member(getNSpace(), proxy_class_name, overloaded_name); +    Setattr(n, "imfuncname", intermediary_function_name); + +    String *proxy_func_name = Getattr(n, "sym:name"); +    Setattr(n, "proxyfuncname", proxy_func_name); +    if (split_proxy_dmodule && +      Len(Getattr(n, "parms")) == 0 && +      Strncmp(proxy_func_name, package, Len(proxy_func_name)) == 0) { +      // If we are in split proxy mode and the function is named like the +      // target package, the D compiler is unable to resolve the ambiguity +      // between the package name and an argument-less function call. +      // TODO: This might occur with nspace as well, augment the check. +      Swig_warning(WARN_D_NAME_COLLISION, input_file, line_number, +	"%s::%s might collide with the package name, consider using %%rename to resolve the ambiguity.\n", +	proxy_class_name, proxy_func_name); +    } + +    writeProxyClassFunction(n); + +    Delete(overloaded_name); + +    // For each function, look if we have to alias in the parent class function +    // for the overload resolution process to work as expected from C++ +    // (http://www.digitalmars.com/d/2.0/function.html#function-inheritance). +    // For multiple overloads, only emit the alias directive once (for the +    // last method, »sym:nextSibling« is null then). +    // Smart pointer classes do not mirror the inheritance hierarchy of the +    // underlying types, so aliasing the base class methods in is not required +    // for them. +    // DMD BUG: We have to emit the alias after the last function because +    // taking a delegate in the overload checking code fails otherwise +    // (http://d.puremagic.com/issues/show_bug.cgi?id=4860). +    if (!Getattr(n, "sym:nextSibling") && !is_smart_pointer() && +	!areAllOverloadsOverridden(n)) { +      String *name = Getattr(n, "sym:name"); +      Printf(proxy_class_body_code, "\nalias $dbaseclass.%s %s;\n", name, name); +    } +    return SWIG_OK; +  } + +  /* --------------------------------------------------------------------------- +   * D::staticmemberfunctionHandler() +   * --------------------------------------------------------------------------- */ +  virtual int staticmemberfunctionHandler(Node *n) { +    static_flag = true; + +    Language::staticmemberfunctionHandler(n); + +    String *overloaded_name = getOverloadedName(n); +    String *intermediary_function_name = +      Swig_name_member(getNSpace(), proxy_class_name, overloaded_name); +    Setattr(n, "proxyfuncname", Getattr(n, "sym:name")); +    Setattr(n, "imfuncname", intermediary_function_name); +    writeProxyClassFunction(n); +    Delete(overloaded_name); + +    static_flag = false; +    return SWIG_OK; +  } + +  /* --------------------------------------------------------------------------- +   * D::globalvariableHandler() +   * --------------------------------------------------------------------------- */ +  virtual int globalvariableHandler(Node *n) { +    variable_name = Getattr(n, "sym:name"); +    global_variable_flag = true; +    int ret = Language::globalvariableHandler(n); +    global_variable_flag = false; + +    return ret; +  } + +  /* --------------------------------------------------------------------------- +   * D::membervariableHandler() +   * --------------------------------------------------------------------------- */ +  virtual int membervariableHandler(Node *n) { +    variable_name = Getattr(n, "sym:name"); +    wrapping_member_flag = true; +    variable_wrapper_flag = true; +    Language::membervariableHandler(n); +    wrapping_member_flag = false; +    variable_wrapper_flag = false; + +    return SWIG_OK; +  } + +  /* --------------------------------------------------------------------------- +   * D::staticmembervariableHandler() +   * --------------------------------------------------------------------------- */ +  virtual int staticmembervariableHandler(Node *n) { +    if (GetFlag(n, "feature:d:manifestconst") != 1) { +      Delattr(n, "value"); +    } + +    variable_name = Getattr(n, "sym:name"); +    wrapping_member_flag = true; +    static_flag = true; +    Language::staticmembervariableHandler(n); +    wrapping_member_flag = false; +    static_flag = false; + +    return SWIG_OK; +  } + +  /* --------------------------------------------------------------------------- +   * D::memberconstantHandler() +   * --------------------------------------------------------------------------- */ +  virtual int memberconstantHandler(Node *n) { +    variable_name = Getattr(n, "sym:name"); +    wrapping_member_flag = true; +    Language::memberconstantHandler(n); +    wrapping_member_flag = false; +    return SWIG_OK; +  } + +  /* --------------------------------------------------------------------------- +   * D::constructorHandler() +   * --------------------------------------------------------------------------- */ +  virtual int constructorHandler(Node *n) { +    Language::constructorHandler(n); + +    // Wrappers not wanted for some methods where the parameters cannot be overloadedprocess in D. +    if (Getattr(n, "overload:ignore")) { +      return SWIG_OK; +    } + +    ParmList *l = Getattr(n, "parms"); +    String *tm; +    String *proxy_constructor_code = NewString(""); +    int i; + +    // Holds code for the constructor helper method generated only when the din +    // typemap has code in the pre or post attributes. +    String *helper_code = NewString(""); +    String *helper_args = NewString(""); +    String *pre_code = NewString(""); +    String *post_code = NewString(""); +    String *terminator_code = NewString(""); +    NewString(""); + +    String *overloaded_name = getOverloadedName(n); +    String *mangled_overname = Swig_name_construct(getNSpace(), overloaded_name); +    String *imcall = NewString(""); + +    const String *methodmods = Getattr(n, "feature:d:methodmodifiers"); +    methodmods = methodmods ? methodmods : (is_public(n) ? public_string : protected_string); + +    // Typemaps were attached earlier to the node, get the return type of the +    // call to the C++ constructor wrapper. +    const String *wrapper_return_type = lookupDTypemap(n, "imtype", true); + +    String *imtypeout = Getattr(n, "tmap:imtype:out"); +    if (imtypeout) { +      // The type in the imtype typemap's out attribute overrides the type in +      // the typemap itself. +      wrapper_return_type = imtypeout; +    } + +    Printf(proxy_constructor_code, "\n%s this(", methodmods); +    Printf(helper_code, "static private %s SwigConstruct%s(", +      wrapper_return_type, proxy_class_name); + +    Printv(imcall, im_dmodule_fq_name, ".", mangled_overname, "(", NIL); + +    /* Attach the non-standard typemaps to the parameter list */ +    Swig_typemap_attach_parms("in", l, NULL); +    Swig_typemap_attach_parms("dtype", l, NULL); +    Swig_typemap_attach_parms("din", l, NULL); + +    emit_mark_varargs(l); + +    int gencomma = 0; + +    /* Output each parameter */ +    Parm *p = l; +    for (i = 0; p; i++) { +      if (checkAttribute(p, "varargs:ignore", "1")) { +	// Skip ignored varargs. +	p = nextSibling(p); +	continue; +      } + +      if (checkAttribute(p, "tmap:in:numinputs", "0")) { +	// Skip ignored parameters. +	p = Getattr(p, "tmap:in:next"); +	continue; +      } + +      SwigType *pt = Getattr(p, "type"); +      String *param_type = NewString(""); + +      // Get the D parameter type. +      if ((tm = lookupDTypemap(p, "dtype", true))) { +	const String *inattributes = Getattr(p, "tmap:dtype:inattributes"); +	Printf(param_type, "%s%s", inattributes ? inattributes : empty_string, tm); +      } else { +	Swig_warning(WARN_D_TYPEMAP_DTYPE_UNDEF, input_file, line_number, +	  "No dtype typemap defined for %s\n", SwigType_str(pt, 0)); +      } + +      if (gencomma) +	Printf(imcall, ", "); + +      String *arg = makeParameterName(n, p, i, false); +      String *parmtype = 0; + +      // Get the D code to convert the parameter value to the type used in the +      // intermediary D module. +      if ((tm = lookupDTypemap(p, "din"))) { +	Replaceall(tm, "$dinput", arg); +	String *pre = Getattr(p, "tmap:din:pre"); +	if (pre) { +	  replaceClassname(pre, pt); +	  Replaceall(pre, "$dinput", arg); +	  if (Len(pre_code) > 0) +	    Printf(pre_code, "\n"); +	  Printv(pre_code, pre, NIL); +	} +	String *post = Getattr(p, "tmap:din:post"); +	if (post) { +	  replaceClassname(post, pt); +	  Replaceall(post, "$dinput", arg); +	  if (Len(post_code) > 0) +	    Printf(post_code, "\n"); +	  Printv(post_code, post, NIL); +	} +	String *terminator = Getattr(p, "tmap:din:terminator"); +	if (terminator) { +	  replaceClassname(terminator, pt); +	  Replaceall(terminator, "$dinput", arg); +	  if (Len(terminator_code) > 0) +	    Insert(terminator_code, 0, "\n"); +	  Insert(terminator_code, 0, terminator); +	} +	parmtype = Getattr(p, "tmap:din:parmtype"); +	if (parmtype) +	  Replaceall(parmtype, "$dinput", arg); +	Printv(imcall, tm, NIL); +      } else { +	Swig_warning(WARN_D_TYPEMAP_DIN_UNDEF, input_file, line_number, +	  "No din typemap defined for %s\n", SwigType_str(pt, 0)); +      } + +      /* Add parameter to proxy function */ +      if (gencomma) { +	Printf(proxy_constructor_code, ", "); +	Printf(helper_code, ", "); +	Printf(helper_args, ", "); +      } +      Printf(proxy_constructor_code, "%s %s", param_type, arg); +      Printf(helper_code, "%s %s", param_type, arg); +      Printf(helper_args, "%s", parmtype ? parmtype : arg); +      ++gencomma; + +      Delete(parmtype); +      Delete(arg); +      Delete(param_type); +      p = Getattr(p, "tmap:in:next"); +    } + +    Printf(imcall, ")"); + +    Printf(proxy_constructor_code, ")"); +    Printf(helper_code, ")"); + +    // Insert the dconstructor typemap (replacing $directorconnect as needed). +    Hash *attributes = NewHash(); +    String *typemap_lookup_type = Getattr(getCurrentClass(), "classtypeobj"); +    String *construct_tm = Copy(lookupCodeTypemap(n, "dconstructor", +      typemap_lookup_type, WARN_D_TYPEMAP_DCONSTRUCTOR_UNDEF, attributes)); +    if (construct_tm) { +      const bool use_director = (parentNode(n) && Swig_directorclass(n)); +      if (!use_director) { +	Replaceall(construct_tm, "$directorconnect", ""); +      } else { +	String *connect_attr = Getattr(attributes, "tmap:dconstructor:directorconnect"); + +	if (connect_attr) { +	  Replaceall(construct_tm, "$directorconnect", connect_attr); +	} else { +	  Swig_warning(WARN_D_NO_DIRECTORCONNECT_ATTR, input_file, line_number, +	    "\"directorconnect\" attribute missing in %s \"dconstructor\" typemap.\n", +	    Getattr(n, "name")); +	  Replaceall(construct_tm, "$directorconnect", ""); +	} +      } + +      Printv(proxy_constructor_code, " ", construct_tm, NIL); +    } + +    replaceExcode(n, proxy_constructor_code, "dconstructor", attributes); + +    bool is_pre_code = Len(pre_code) > 0; +    bool is_post_code = Len(post_code) > 0; +    bool is_terminator_code = Len(terminator_code) > 0; +    if (is_pre_code || is_post_code || is_terminator_code) { +      Printf(helper_code, " {\n"); +      if (is_pre_code) { +	Printv(helper_code, pre_code, "\n", NIL); +      } +      if (is_post_code) { +	Printf(helper_code, "  try {\n"); +	Printv(helper_code, "    return ", imcall, ";\n", NIL); +	Printv(helper_code, "  } finally {\n", post_code, "\n    }", NIL); +      } else { +	Printv(helper_code, "  return ", imcall, ";", NIL); +      } +      if (is_terminator_code) { +	Printv(helper_code, "\n", terminator_code, NIL); +      } +      Printf(helper_code, "\n}\n"); +      String *helper_name = NewStringf("%s.SwigConstruct%s(%s)", +	proxy_class_name, proxy_class_name, helper_args); +      Replaceall(proxy_constructor_code, "$imcall", helper_name); +      Delete(helper_name); +    } else { +      Replaceall(proxy_constructor_code, "$imcall", imcall); +    } + +    Printv(proxy_class_body_code, proxy_constructor_code, "\n", NIL); + +    Delete(helper_args); +    Delete(pre_code); +    Delete(post_code); +    Delete(terminator_code); +    Delete(construct_tm); +    Delete(attributes); +    Delete(overloaded_name); +    Delete(imcall); + +    return SWIG_OK; +  } + +  /* --------------------------------------------------------------------------- +   * D::destructorHandler() +   * --------------------------------------------------------------------------- */ +  virtual int destructorHandler(Node *n) { +    Language::destructorHandler(n); +    String *symname = Getattr(n, "sym:name"); + +    Printv(destructor_call, im_dmodule_fq_name, ".", Swig_name_destroy(getNSpace(),symname), "(cast(void*)swigCPtr)", NIL); +    const String *methodmods = Getattr(n, "feature:d:methodmodifiers"); +    if (methodmods) +      Setattr(getCurrentClass(), "destructmethodmodifiers", methodmods); + +    return SWIG_OK; +  } + +  /* --------------------------------------------------------------------------- +   * D::classHandler() +   * --------------------------------------------------------------------------- */ +  virtual int classHandler(Node *n) { +    String *nspace = getNSpace(); +    File *class_file = NULL; + +    proxy_class_name = Copy(Getattr(n, "sym:name")); +    if (nspace) { +      proxy_class_qname = NewStringf("%s.%s", nspace, proxy_class_name); +    } else { +      proxy_class_qname = Copy(proxy_class_name); +    } + +    if (!addSymbol(proxy_class_name, n, nspace)) { +      return SWIG_ERROR; +    } + +    assertClassNameValidity(proxy_class_name); + +    if (split_proxy_dmodule) { +      String *output_directory = outputDirectory(nspace); +      String *filename = NewStringf("%s%s.d", output_directory, proxy_class_name); +      class_file = NewFile(filename, "w", SWIG_output_files()); +      Delete(output_directory); +      if (!class_file) { +	FileErrorDisplay(filename); +	Exit(EXIT_FAILURE); +      } +      Append(filenames_list, Copy(filename)); +      Delete(filename); + +      emitBanner(class_file); +      if (nspace) { +        Printf(class_file, "module %s%s.%s;\n", package, nspace, proxy_class_name); +      } else { +        Printf(class_file, "module %s%s;\n", package, proxy_class_name); +      } +      Printf(class_file, "\nstatic import %s;\n", im_dmodule_fq_name); +    } + +    Clear(proxy_class_imports); +    Clear(proxy_class_enums_code); +    Clear(proxy_class_body_code); +    Clear(proxy_class_epilogue_code); +    Clear(proxy_class_code); +    Clear(destructor_call); + + +    // Traverse the tree for this class, using the *Handler()s to generate code +    // to the proxy_class_* variables. +    Language::classHandler(n); + + +    writeProxyClassAndUpcasts(n); +    writeDirectorConnectWrapper(n); + +    Replaceall(proxy_class_code, "$dclassname", proxy_class_name); + +    String *dclazzname = Swig_name_member(getNSpace(), proxy_class_name, ""); +    Replaceall(proxy_class_code, "$dclazzname", dclazzname); +    Delete(dclazzname); + +    if (split_proxy_dmodule) { +      Printv(class_file, global_proxy_imports, NIL); +      Printv(class_file, proxy_class_imports, NIL); + +      replaceModuleVariables(proxy_class_code); +      Printv(class_file, proxy_class_code, NIL); + +      Delete(class_file); +    } else { +      Printv(proxyImportsBuffer(getNSpace()), proxy_class_imports, NIL); +      Printv(proxyCodeBuffer(getNSpace()), proxy_class_code, NIL); +    } + +    Delete(proxy_class_qname); +    proxy_class_qname = NULL; +    Delete(proxy_class_name); +    proxy_class_name = NULL; + +    return SWIG_OK; +  } + +  /* --------------------------------------------------------------------------- +   * D::constantWrapper() +   * +   * Used for wrapping constants declared by #define or %constant and also for +   * (primitive) static member constants initialised inline. +   * +   * If the %dmanifestconst feature is used, the C/C++ constant value is used to +   * initialize a D »const«. If not, a »getter« method is generated which +   * retrieves the value via a call to the C wrapper. However, if there is a +   * %dconstvalue specified, it overrides all other settings. +   * --------------------------------------------------------------------------- */ +  virtual int constantWrapper(Node *n) { +    String *symname = Getattr(n, "sym:name"); +    if (!addSymbol(symname, n)) +      return SWIG_ERROR; + +    // The %dmanifestconst feature determines if a D manifest constant +    // (const/enum) or a getter function is created. +    if (GetFlag(n, "feature:d:manifestconst") != 1) { +      // Default constant handling will work with any type of C constant. It +      // generates a getter function (which is the same as a read only property +      // in D) which retrieves the value via by calling the C wrapper. +      // Note that this is only called for global constants, static member +      // constants are already handled in staticmemberfunctionHandler(). + +      Swig_save("constantWrapper", n, "value", NIL); +      Swig_save("constantWrapper", n, "tmap:ctype:out", "tmap:imtype:out", "tmap:dtype:out", "tmap:out:null", "tmap:imtype:outattributes", "tmap:dtype:outattributes", NIL); + +      // Add the stripped quotes back in. +      String *old_value = Getattr(n, "value"); +      SwigType *t = Getattr(n, "type"); +      if (SwigType_type(t) == T_STRING) { +	Setattr(n, "value", NewStringf("\"%s\"", old_value)); +	Delete(old_value); +      } else if (SwigType_type(t) == T_CHAR) { +	Setattr(n, "value", NewStringf("\'%s\'", old_value)); +	Delete(old_value); +      } + +      SetFlag(n, "feature:immutable"); +      int result = globalvariableHandler(n); + +      Swig_restore(n); +      return result; +    } + +    String *constants_code = NewString(""); +    SwigType *t = Getattr(n, "type"); +    SwigType *valuetype = Getattr(n, "valuetype"); +    ParmList *l = Getattr(n, "parms"); + +    // Attach the non-standard typemaps to the parameter list. +    Swig_typemap_attach_parms("dtype", l, NULL); + +    // Get D return type. +    String *return_type = NewString(""); +    String *tm; +    if ((tm = lookupDTypemap(n, "dtype"))) { +      String *dtypeout = Getattr(n, "tmap:dtype:out"); +      if (dtypeout) { +	// The type in the out attribute of the typemap overrides the type +	// in the dtype typemap. +	tm = dtypeout; +	replaceClassname(tm, t); +      } +      Printf(return_type, "%s", tm); +    } else { +      Swig_warning(WARN_D_TYPEMAP_DTYPE_UNDEF, input_file, line_number, +	"No dtype typemap defined for %s\n", SwigType_str(t, 0)); +    } + +    const String *itemname = wrapping_member_flag ? variable_name : symname; + +    String *attributes = Getattr(n, "feature:d:methodmodifiers"); +    if (attributes) { +      attributes = Copy(attributes); +    } else { +      attributes = Copy(is_public(n) ? public_string : protected_string); +    } + +    if (d_version == 1) { +      if (static_flag) { +	Printv(attributes, " static", NIL); +      } +      Printf(constants_code, "\n%s const %s %s = ", attributes, return_type, itemname); +    } else { +      Printf(constants_code, "\n%s enum %s %s = ", attributes, return_type, itemname); +    } +    Delete(attributes); + +    // Retrieve the override value set via %dconstvalue, if any. +    String *override_value = Getattr(n, "feature:d:constvalue"); +    if (override_value) { +      Printf(constants_code, "%s;\n", override_value); +    } else { +      // Just take the value from the C definition and hope it compiles in D. +      if (Getattr(n, "wrappedasconstant")) { +	if (SwigType_type(valuetype) == T_CHAR) +          Printf(constants_code, "\'%(escape)s\';\n", Getattr(n, "staticmembervariableHandler:value")); +	else +          Printf(constants_code, "%s;\n", Getattr(n, "staticmembervariableHandler:value")); +      } else { +	// Add the stripped quotes back in. +	String* value = Getattr(n, "value"); +	if (SwigType_type(t) == T_STRING) { +	  Printf(constants_code, "\"%s\";\n", value); +	} else if (SwigType_type(t) == T_CHAR) { +	  Printf(constants_code, "\'%s\';\n", value); +	} else { +	  Printf(constants_code, "%s;\n", value); +	} +      } +    } + +    // Emit the generated code to appropriate place. +    if (wrapping_member_flag) { +      Printv(proxy_class_body_code, constants_code, NIL); +    } else { +      Printv(proxyCodeBuffer(getNSpace()), constants_code, NIL); +    } + +    // Cleanup. +    Delete(return_type); +    Delete(constants_code); + +    return SWIG_OK; +  } + +  /* --------------------------------------------------------------------------- +   * D::functionWrapper() +   * +   * Generates the C wrapper code for a function and the corresponding +   * declaration in the wrap D module. +   * --------------------------------------------------------------------------- */ +  virtual int functionWrapper(Node *n) { +    String *symname = Getattr(n, "sym:name"); +    SwigType *t = Getattr(n, "type"); +    ParmList *l = Getattr(n, "parms"); +    String *tm; +    Parm *p; +    int i; +    String *c_return_type = NewString(""); +    String *im_return_type = NewString(""); +    String *cleanup = NewString(""); +    String *outarg = NewString(""); +    String *body = NewString(""); +    int num_arguments = 0; +    bool is_void_return; +    String *overloaded_name = getOverloadedName(n); + +    if (!Getattr(n, "sym:overloaded")) { +      if (!addSymbol(Getattr(n, "sym:name"), n)) +	return SWIG_ERROR; +    } + +    // A new wrapper function object +    Wrapper *f = NewWrapper(); + +    // Make a wrapper name for this function +    String *wname = Swig_name_wrapper(overloaded_name); + +    /* Attach the non-standard typemaps to the parameter list. */ +    Swig_typemap_attach_parms("ctype", l, f); +    Swig_typemap_attach_parms("imtype", l, f); + +    /* Get return types */ +    if ((tm = lookupDTypemap(n, "ctype"))) { +      String *ctypeout = Getattr(n, "tmap:ctype:out"); +      if (ctypeout) { +	// The type in the ctype typemap's out attribute overrides the type in +	// the typemap itself. +	tm = ctypeout; +      } +      Printf(c_return_type, "%s", tm); +    } else { +      Swig_warning(WARN_D_TYPEMAP_CTYPE_UNDEF, input_file, line_number, +	"No ctype typemap defined for %s\n", SwigType_str(t, 0)); +    } + +    if ((tm = lookupDTypemap(n, "imtype"))) { +      String *imtypeout = Getattr(n, "tmap:imtype:out"); +      if (imtypeout) { +	// The type in the imtype typemap's out attribute overrides the type in +	// the typemap itself. +	tm = imtypeout; +      } +      Printf(im_return_type, "%s", tm); +    } else { +      Swig_warning(WARN_D_TYPEMAP_IMTYPE_UNDEF, input_file, line_number, "No imtype typemap defined for %s\n", SwigType_str(t, 0)); +    } + +    is_void_return = (Cmp(c_return_type, "void") == 0); +    if (!is_void_return) +      Wrapper_add_localv(f, "jresult", c_return_type, "jresult", NIL); + +    Printv(f->def, " SWIGEXPORT ", c_return_type, " ", wname, "(", NIL); + +    // Emit all of the local variables for holding arguments. +    emit_parameter_variables(l, f); + +    /* Attach the standard typemaps */ +    emit_attach_parmmaps(l, f); + +    // Parameter overloading +    Setattr(n, "wrap:parms", l); +    Setattr(n, "wrap:name", wname); + +    // Wrappers not wanted for some methods where the parameters cannot be overloaded in D +    if (Getattr(n, "sym:overloaded")) { +      // Emit warnings for the few cases that can't be overloaded in D and give up on generating wrapper +      Swig_overload_check(n); +      if (Getattr(n, "overload:ignore")) { +	DelWrapper(f); +	return SWIG_OK; +      } +    } + +    // Collect the parameter list for the intermediary D module declaration of +    // the generated wrapper function. +    String *im_dmodule_parameters = NewString("("); + +    /* Get number of required and total arguments */ +    num_arguments = emit_num_arguments(l); +    int gencomma = 0; + +    // Now walk the function parameter list and generate code to get arguments +    for (i = 0, p = l; i < num_arguments; i++) { + +      while (checkAttribute(p, "tmap:in:numinputs", "0")) { +	p = Getattr(p, "tmap:in:next"); +      } + +      SwigType *pt = Getattr(p, "type"); +      String *ln = Getattr(p, "lname"); +      String *im_param_type = NewString(""); +      String *c_param_type = NewString(""); +      String *arg = NewString(""); + +      Printf(arg, "j%s", ln); + +      /* Get the ctype types of the parameter */ +      if ((tm = lookupDTypemap(p, "ctype", true))) { +	Printv(c_param_type, tm, NIL); +      } else { +	Swig_warning(WARN_D_TYPEMAP_CTYPE_UNDEF, input_file, line_number, "No ctype typemap defined for %s\n", SwigType_str(pt, 0)); +      } + +      /* Get the intermediary class parameter types of the parameter */ +      if ((tm = lookupDTypemap(p, "imtype", true))) { +	const String *inattributes = Getattr(p, "tmap:imtype:inattributes"); +	Printf(im_param_type, "%s%s", inattributes ? inattributes : empty_string, tm); +      } else { +	Swig_warning(WARN_D_TYPEMAP_IMTYPE_UNDEF, input_file, line_number, "No imtype typemap defined for %s\n", SwigType_str(pt, 0)); +      } + +      /* Add parameter to intermediary class method */ +      if (gencomma) +	Printf(im_dmodule_parameters, ", "); +      Printf(im_dmodule_parameters, "%s %s", im_param_type, arg); + +      // Add parameter to C function +      Printv(f->def, gencomma ? ", " : "", c_param_type, " ", arg, NIL); + +      gencomma = 1; + +      // Get typemap for this argument +      if ((tm = Getattr(p, "tmap:in"))) { +	canThrow(n, "in", p); +	Replaceall(tm, "$input", arg); +	Setattr(p, "emit:input", arg); +	Printf(f->code, "%s\n", tm); +	p = Getattr(p, "tmap:in:next"); +      } else { +	Swig_warning(WARN_TYPEMAP_IN_UNDEF, input_file, line_number, "Unable to use type %s as a function argument.\n", SwigType_str(pt, 0)); +	p = nextSibling(p); +      } +      Delete(im_param_type); +      Delete(c_param_type); +      Delete(arg); +    } + +    /* Insert constraint checking code */ +    for (p = l; p;) { +      if ((tm = Getattr(p, "tmap:check"))) { +	canThrow(n, "check", p); +	Replaceall(tm, "$input", Getattr(p, "emit:input")); +	Printv(f->code, tm, "\n", NIL); +	p = Getattr(p, "tmap:check:next"); +      } else { +	p = nextSibling(p); +      } +    } + +    /* Insert cleanup code */ +    for (p = l; p;) { +      if ((tm = Getattr(p, "tmap:freearg"))) { +	canThrow(n, "freearg", p); +	Replaceall(tm, "$input", Getattr(p, "emit:input")); +	Printv(cleanup, tm, "\n", NIL); +	p = Getattr(p, "tmap:freearg:next"); +      } else { +	p = nextSibling(p); +      } +    } + +    /* Insert argument output code */ +    for (p = l; p;) { +      if ((tm = Getattr(p, "tmap:argout"))) { +	canThrow(n, "argout", p); +	Replaceall(tm, "$result", "jresult"); +	Replaceall(tm, "$input", Getattr(p, "emit:input")); +	Printv(outarg, tm, "\n", NIL); +	p = Getattr(p, "tmap:argout:next"); +      } else { +	p = nextSibling(p); +      } +    } + +    // Look for usage of throws typemap and the canthrow flag +    ParmList *throw_parm_list = NULL; +    if ((throw_parm_list = Getattr(n, "catchlist"))) { +      Swig_typemap_attach_parms("throws", throw_parm_list, f); +      for (p = throw_parm_list; p; p = nextSibling(p)) { +	if (Getattr(p, "tmap:throws")) { +	  canThrow(n, "throws", p); +	} +      } +    } + +    String *null_attribute = 0; +    // Now write code to make the function call +    if (!native_function_flag) { + +      Swig_director_emit_dynamic_cast(n, f); +      String *actioncode = emit_action(n); + +      /* Return value if necessary  */ +      if ((tm = Swig_typemap_lookup_out("out", n, Swig_cresult_name(), f, actioncode))) { +	canThrow(n, "out", n); +	Replaceall(tm, "$result", "jresult"); + +	if (GetFlag(n, "feature:new")) +	  Replaceall(tm, "$owner", "1"); +	else +	  Replaceall(tm, "$owner", "0"); + +	Printf(f->code, "%s", tm); +	null_attribute = Getattr(n, "tmap:out:null"); +	if (Len(tm)) +	  Printf(f->code, "\n"); +      } else { +	Swig_warning(WARN_TYPEMAP_OUT_UNDEF, input_file, line_number, "Unable to use return type %s in function %s.\n", SwigType_str(t, 0), Getattr(n, "name")); +      } +      emit_return_variable(n, t, f); +    } + +    /* Output argument output code */ +    Printv(f->code, outarg, NIL); + +    /* Output cleanup code */ +    Printv(f->code, cleanup, NIL); + +    /* Look to see if there is any newfree cleanup code */ +    if (GetFlag(n, "feature:new")) { +      if ((tm = Swig_typemap_lookup("newfree", n, Swig_cresult_name(), 0))) { +	canThrow(n, "newfree", n); +	Printf(f->code, "%s\n", tm); +      } +    } + +    /* See if there is any return cleanup code */ +    if (!native_function_flag) { +      if ((tm = Swig_typemap_lookup("ret", n, Swig_cresult_name(), 0))) { +	canThrow(n, "ret", n); +	Printf(f->code, "%s\n", tm); +      } +    } + +    // Complete D im parameter list and emit the declaration/binding code. +    Printv(im_dmodule_parameters, ")", NIL); +    writeImDModuleFunction(overloaded_name, im_return_type, +      im_dmodule_parameters, wname); +    Delete(im_dmodule_parameters); + +    // Finish C function header. +    Printf(f->def, ") {"); + +    if (!is_void_return) +      Printv(f->code, "    return jresult;\n", NIL); +    Printf(f->code, "}\n"); + +    /* Substitute the cleanup code */ +    Replaceall(f->code, "$cleanup", cleanup); + +    /* Substitute the function name */ +    Replaceall(f->code, "$symname", symname); + +    /* Contract macro modification */ +    if (Replaceall(f->code, "SWIG_contract_assert(", "SWIG_contract_assert($null, ") > 0) { +      Setattr(n, "d:canthrow", "1"); +    } + +    if (!null_attribute) +      Replaceall(f->code, "$null", "0"); +    else +      Replaceall(f->code, "$null", null_attribute); + +    /* Dump the function out */ +    if (!native_function_flag) { +      Wrapper_print(f, f_wrappers); + +      // Handle %exception which sets the canthrow attribute. +      if (Getattr(n, "feature:except:canthrow")) { +	Setattr(n, "d:canthrow", "1"); +      } + +      // A very simple check (it is not foolproof) to assist typemap writers +      // with setting the correct features when the want to throw D exceptions +      // from C++ code. It checks for the common methods which set +      // a pending D exception and issues a warning if one of them has been found +      // in the typemap, but the »canthrow« attribute/feature is not set. +      if (!Getattr(n, "d:canthrow")) { +	if (Strstr(f->code, "SWIG_exception")) { +	  Swig_warning(WARN_D_CANTHROW_MISSING, input_file, line_number, +	  "C code contains a call to SWIG_exception and D code does not handle pending exceptions via the canthrow attribute.\n"); +	} else if (Strstr(f->code, "SWIG_DSetPendingException")) { +	  Swig_warning(WARN_D_CANTHROW_MISSING, input_file, line_number, +	  "C code contains a call to a SWIG_DSetPendingException method and D code does not handle pending exceptions via the canthrow attribute.\n"); +	} +      } +    } + +    // If we are not processing an enum or constant, and we were not generating +    // a wrapper function which will be accessed via a proxy class, write a +    // function to the proxy D module. +    if (!is_wrapping_class()) { +      writeProxyDModuleFunction(n); +    } + +    // If we are processing a public member variable, write the property-style +    // member function to the proxy class. +    if (wrapping_member_flag) { +      Setattr(n, "proxyfuncname", variable_name); +      Setattr(n, "imfuncname", symname); + +      writeProxyClassFunction(n); +    } + +    Delete(c_return_type); +    Delete(im_return_type); +    Delete(cleanup); +    Delete(outarg); +    Delete(body); +    Delete(overloaded_name); +    DelWrapper(f); +    return SWIG_OK; +  } + +  /* --------------------------------------------------------------------------- +   * D::nativeWrapper() +   * --------------------------------------------------------------------------- */ +  virtual int nativeWrapper(Node *n) { +    String *wrapname = Getattr(n, "wrap:name"); + +    if (!addSymbol(wrapname, n)) +      return SWIG_ERROR; + +    if (Getattr(n, "type")) { +      Swig_save("nativeWrapper", n, "name", NIL); +      Setattr(n, "name", wrapname); +      native_function_flag = true; +      functionWrapper(n); +      Swig_restore(n); +      native_function_flag = false; +    } else { +      Swig_error(input_file, line_number, "No return type for %%native method %s.\n", Getattr(n, "wrap:name")); +    } + +    return SWIG_OK; +  } + +  /* --------------------------------------------------------------------------- +   * D::classDirector() +   * --------------------------------------------------------------------------- */ +  virtual int classDirector(Node *n) { +    String *nspace = Getattr(n, "sym:nspace"); +    proxy_class_name = NewString(Getattr(n, "sym:name")); +    if (nspace) { +      proxy_class_qname = NewStringf("%s.%s", nspace, proxy_class_name); +    } else { +      proxy_class_qname = Copy(proxy_class_name); +    } + +    int success = Language::classDirector(n); + +    Delete(proxy_class_qname); +    proxy_class_qname = NULL; +    Delete(proxy_class_name); +    proxy_class_name = NULL; + +    return success; +  } + + +  /* --------------------------------------------------------------------------- +   * D::classDirectorInit() +   * --------------------------------------------------------------------------- */ +  virtual int classDirectorInit(Node *n) { +    Delete(director_ctor_code); +    director_ctor_code = NewString("$director_new"); + +    // Write C++ director class declaration, for example: +    // class SwigDirector_myclass : public myclass, public Swig::Director { +    String *classname = Swig_class_name(n); +    String *directorname = directorClassName(n); +    String *declaration = Swig_class_declaration(n, directorname); +    const String *base = Getattr(n, "classtype"); + +    Printf(f_directors_h, +      "%s : public %s, public Swig::Director {\n", declaration, base); +    Printf(f_directors_h, "\npublic:\n"); + +    Delete(declaration); +    Delete(directorname); +    Delete(classname); + +    // Stash for later. +    Setattr(n, "director:ctor", NewString("Swig::Director()")); + +    // Keep track of the director methods for this class. +    first_class_dmethod = curr_class_dmethod = n_dmethods; + +    director_callback_typedefs = NewString(""); +    director_callback_pointers = NewString(""); +    director_dcallbacks_code = NewString(""); + +    return Language::classDirectorInit(n); +  } + +  /* --------------------------------------------------------------------------- +   * D::classDirectorMethod() +   * +   * Emit a virtual director method to pass a method call on to the +   * underlying D object. +   * --------------------------------------------------------------------------- */ +  virtual int classDirectorMethod(Node *n, Node *parent, String *super) { +    String *classname = Getattr(parent, "sym:name"); +    String *c_classname = Getattr(parent, "name"); +    String *name = Getattr(n, "name"); +    String *symname = Getattr(n, "sym:name"); +    SwigType *returntype = Getattr(n, "type"); +    String *overloaded_name = getOverloadedName(n); +    String *storage = Getattr(n, "storage"); +    String *value = Getattr(n, "value"); +    String *decl = Getattr(n, "decl"); +    String *declaration = NewString(""); +    String *tm; +    Parm *p; +    int i; +    Wrapper *w = NewWrapper(); +    ParmList *l = Getattr(n, "parms"); +    bool is_void = !(Cmp(returntype, "void")); +    String *qualified_return = 0; +    bool pure_virtual = (!(Cmp(storage, "virtual")) && !(Cmp(value, "0"))); +    int status = SWIG_OK; +    bool output_director = true; +    String *dirclassname = directorClassName(parent); +    String *qualified_name = NewStringf("%s::%s", dirclassname, name); +    SwigType *c_ret_type = NULL; +    String *dcallback_call_args = NewString(""); +    String *imclass_dmethod; +    String *callback_typedef_parms = NewString(""); +    String *delegate_parms = NewString(""); +    String *proxy_method_param_list = NewString(""); +    String *proxy_callback_return_type = NewString(""); +    String *callback_def = NewString(""); +    String *callback_code = NewString(""); +    String *imcall_args = NewString(""); +    bool ignored_method = GetFlag(n, "feature:ignore") ? true : false; + +    // Kludge Alert: functionWrapper sets sym:overload properly, but it +    // isn't at this point, so we have to manufacture it ourselves. At least +    // we're consistent with the sym:overload name in functionWrapper. (?? when +    // does the overloaded method name get set?) + +    imclass_dmethod = NewStringf("SwigDirector_%s", Swig_name_member(getNSpace(), classname, overloaded_name)); + +    qualified_return = SwigType_rcaststr(returntype, "c_result"); + +    if (!is_void && (!ignored_method || pure_virtual)) { +      if (!SwigType_isclass(returntype)) { +	if (!(SwigType_ispointer(returntype) || SwigType_isreference(returntype))) { +	  String *construct_result = NewStringf("= SwigValueInit< %s >()", SwigType_lstr(returntype, 0)); +	  Wrapper_add_localv(w, "c_result", SwigType_lstr(returntype, "c_result"), construct_result, NIL); +	  Delete(construct_result); +	} else { +	  String *base_typename = SwigType_base(returntype); +	  String *resolved_typename = SwigType_typedef_resolve_all(base_typename); +	  Symtab *symtab = Getattr(n, "sym:symtab"); +	  Node *typenode = Swig_symbol_clookup(resolved_typename, symtab); + +	  if (SwigType_ispointer(returntype) || (typenode && Getattr(typenode, "abstracts"))) { +	    /* initialize pointers to something sane. Same for abstract +	       classes when a reference is returned. */ +	    Wrapper_add_localv(w, "c_result", SwigType_lstr(returntype, "c_result"), "= 0", NIL); +	  } else { +	    /* If returning a reference, initialize the pointer to a sane +	       default - if a D exception occurs, then the pointer returns +	       something other than a NULL-initialized reference. */ +	    SwigType *noref_type = SwigType_del_reference(Copy(returntype)); +	    String *noref_ltype = SwigType_lstr(noref_type, 0); +	    String *return_ltype = SwigType_lstr(returntype, 0); + +	    Wrapper_add_localv(w, "result_default", "static", noref_ltype, "result_default", NIL); +	    Wrapper_add_localv(w, "c_result", return_ltype, "c_result", NIL); +	    Printf(w->code, "result_default = SwigValueInit< %s >();\n", noref_ltype); +	    Printf(w->code, "c_result = &result_default;\n"); +	    Delete(return_ltype); +	    Delete(noref_ltype); +	    Delete(noref_type); +	  } + +	  Delete(base_typename); +	  Delete(resolved_typename); +	} +      } else { +	SwigType *vt; + +	vt = cplus_value_type(returntype); +	if (!vt) { +	  Wrapper_add_localv(w, "c_result", SwigType_lstr(returntype, "c_result"), NIL); +	} else { +	  Wrapper_add_localv(w, "c_result", SwigType_lstr(vt, "c_result"), NIL); +	  Delete(vt); +	} +      } +    } + +    /* Create the intermediate class wrapper */ +    tm = lookupDTypemap(n, "imtype"); +    if (tm) { +      String *imtypeout = Getattr(n, "tmap:imtype:out"); +      if (imtypeout) { +	// The type in the imtype typemap's out attribute overrides the type +	// in the typemap. +	tm = imtypeout; +      } +      Printf(callback_def, "\nprivate extern(C) %s swigDirectorCallback_%s_%s(void* dObject", tm, classname, overloaded_name); +      Printv(proxy_callback_return_type, tm, NIL); +    } else { +      Swig_warning(WARN_D_TYPEMAP_IMTYPE_UNDEF, input_file, line_number, +	"No imtype typemap defined for %s\n", SwigType_str(returntype, 0)); +    } + +    if ((c_ret_type = Swig_typemap_lookup("ctype", n, "", 0))) { +      if (!is_void && !ignored_method) { +	String *jretval_decl = NewStringf("%s jresult", c_ret_type); +	Wrapper_add_localv(w, "jresult", jretval_decl, "= 0", NIL); +	Delete(jretval_decl); +      } +    } else { +      Swig_warning(WARN_D_TYPEMAP_CTYPE_UNDEF, input_file, line_number, +	"No ctype typemap defined for %s for use in %s::%s (skipping director method)\n", +	SwigType_str(returntype, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); +      output_director = false; +    } + +    Swig_director_parms_fixup(l); + +    // Attach the standard typemaps. +    Swig_typemap_attach_parms("out", l, 0); +    Swig_typemap_attach_parms("ctype", l, 0); +    Swig_typemap_attach_parms("imtype", l, 0); +    Swig_typemap_attach_parms("dtype", l, 0); +    Swig_typemap_attach_parms("directorin", l, w); +    Swig_typemap_attach_parms("ddirectorin", l, 0); +    Swig_typemap_attach_parms("directorargout", l, w); + +    // Preamble code. +    if (!ignored_method) +      Printf(w->code, "if (!swig_callback_%s) {\n", overloaded_name); + +    if (!pure_virtual) { +      String *super_call = Swig_method_call(super, l); +      if (is_void) { +	Printf(w->code, "%s;\n", super_call); +	if (!ignored_method) +	  Printf(w->code, "return;\n"); +      } else { +	Printf(w->code, "return %s;\n", super_call); +      } +      Delete(super_call); +    } else { +      Printf(w->code, "Swig::DirectorPureVirtualException::raise(\"%s::%s\");\n", SwigType_namestr(c_classname), SwigType_namestr(name)); +      if (!is_void) +	Printf(w->code, "return %s;", qualified_return); +      else if (!ignored_method) +	Printf(w->code, "return;\n"); +    } + +    if (!ignored_method) +      Printf(w->code, "} else {\n"); + +    // Go through argument list. +    for (i = 0, p = l; p; ++i) { +      /* Is this superfluous? */ +      while (checkAttribute(p, "tmap:directorin:numinputs", "0")) { +	p = Getattr(p, "tmap:directorin:next"); +      } + +      SwigType *pt = Getattr(p, "type"); +      String *ln = makeParameterName(n, p, i, false); +      String *c_param_type = NULL; +      String *c_decl = NewString(""); +      String *arg = NewString(""); + +      Printf(arg, "j%s", ln); + +      // Add each parameter to the D callback invocation arguments. +      Printf(dcallback_call_args, ", %s", arg); + +      /* Get parameter's intermediary C type */ +      if ((c_param_type = lookupDTypemap(p, "ctype", true))) { +	String *ctypeout = Getattr(p, "tmap:ctype:out"); +	if (ctypeout) { +	  // The type in the ctype typemap's out attribute overrides the type +	  // in the typemap itself. +	  c_param_type = ctypeout; +	} + +	/* Add to local variables */ +	Printf(c_decl, "%s %s", c_param_type, arg); +	if (!ignored_method) +	  Wrapper_add_localv(w, arg, c_decl, (!(SwigType_ispointer(pt) || SwigType_isreference(pt)) ? "" : "= 0"), NIL); + +	/* Add input marshalling code */ +	if ((tm = Getattr(p, "tmap:directorin"))) { + +	  Setattr(p, "emit:directorinput", arg); +	  Replaceall(tm, "$input", arg); +	  Replaceall(tm, "$owner", "0"); + +	  if (Len(tm)) +	    if (!ignored_method) +	      Printf(w->code, "%s\n", tm); + +	  // Add parameter type to the C typedef for the D callback function. +	  Printf(callback_typedef_parms, ", %s", c_param_type); + +	  /* Add parameter to the intermediate class code if generating the +	   * intermediate's upcall code */ +	  if ((tm = lookupDTypemap(p, "imtype", true))) { +	    String *imtypeout = Getattr(p, "tmap:imtype:out"); +	    if (imtypeout) { +	      // The type in the imtype typemap's out attribute overrides the +	      // type in the typemap itself. +	      tm = imtypeout; +	    } +	    const String *im_directorinattributes = Getattr(p, "tmap:imtype:directorinattributes"); + +	    // TODO: Is this copy really needed? +	    String *din = Copy(lookupDTypemap(p, "ddirectorin", true)); + +	    if (din) { +	      Replaceall(din, "$winput", ln); + +	      Printf(delegate_parms, ", "); +	      if (i > 0) { +		Printf(proxy_method_param_list, ", "); +		Printf(imcall_args, ", "); +	      } +	      Printf(delegate_parms, "%s%s %s", im_directorinattributes ? im_directorinattributes : empty_string, tm, ln); + +	      if (Cmp(din, ln)) { +		Printv(imcall_args, din, NIL); +	      } else { +		Printv(imcall_args, ln, NIL); +	      } + +	      Delete(din); + +	      // Get the parameter type in the proxy D class (used later when +	      // generating the overload checking code for the directorConnect +	      // function). +	      if ((tm = lookupDTypemap(p, "dtype", true))) { +		Printf(proxy_method_param_list, "%s", tm); +	      } else { +		Swig_warning(WARN_D_TYPEMAP_DTYPE_UNDEF, input_file, line_number, +	          "No dtype typemap defined for %s\n", SwigType_str(pt, 0)); +	      } +	    } else { +	      Swig_warning(WARN_D_TYPEMAP_DDIRECTORIN_UNDEF, input_file, line_number, +	        "No ddirectorin typemap defined for %s for use in %s::%s (skipping director method)\n", +		SwigType_str(pt, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); +	      output_director = false; +	    } +	  } else { +	    Swig_warning(WARN_D_TYPEMAP_IMTYPE_UNDEF, input_file, line_number, +	      "No imtype typemap defined for %s for use in %s::%s (skipping director method)\n", +	      SwigType_str(pt, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); +	    output_director = false; +	  } + +	  p = Getattr(p, "tmap:directorin:next"); +	} else { +	  Swig_warning(WARN_D_TYPEMAP_DDIRECTORIN_UNDEF, input_file, line_number, +	    "No or improper directorin typemap defined for argument %s for use in %s::%s (skipping director method)\n", +	    SwigType_str(pt, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); +	  p = nextSibling(p); +	  output_director = false; +	} +      } else { +	Swig_warning(WARN_D_TYPEMAP_CTYPE_UNDEF, input_file, line_number, +	  "No ctype typemap defined for %s for use in %s::%s (skipping director method)\n", +	  SwigType_str(pt, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); +	output_director = false; +	p = nextSibling(p); +      } + +      Delete(arg); +      Delete(c_decl); +      Delete(c_param_type); +      Delete(ln); +    } + +    /* header declaration, start wrapper definition */ +    String *target; +    SwigType *rtype = Getattr(n, "conversion_operator") ? 0 : Getattr(n, "classDirectorMethods:type"); +    target = Swig_method_decl(rtype, decl, qualified_name, l, 0); +    Printf(w->def, "%s", target); +    Delete(qualified_name); +    Delete(target); +    target = Swig_method_decl(rtype, decl, name, l, 1); +    Printf(declaration, "    virtual %s", target); +    Delete(target); + +    // Add any exception specifications to the methods in the director class +    if (Getattr(n, "noexcept")) { +      Append(w->def, " noexcept"); +      Append(declaration, " noexcept"); +    } +    ParmList *throw_parm_list = NULL; +    if ((throw_parm_list = Getattr(n, "throws")) || Getattr(n, "throw")) { +      int gencomma = 0; + +      Append(w->def, " throw("); +      Append(declaration, " throw("); + +      if (throw_parm_list) +	Swig_typemap_attach_parms("throws", throw_parm_list, 0); +      for (p = throw_parm_list; p; p = nextSibling(p)) { +	if (Getattr(p, "tmap:throws")) { +	  if (gencomma++) { +	    Append(w->def, ", "); +	    Append(declaration, ", "); +	  } +	  Printf(w->def, "%s", SwigType_str(Getattr(p, "type"), 0)); +	  Printf(declaration, "%s", SwigType_str(Getattr(p, "type"), 0)); +	} +      } + +      Append(w->def, ")"); +      Append(declaration, ")"); +    } + +    Append(w->def, " {"); +    Append(declaration, ";\n"); + +    // Finish the callback function declaraction. +    Printf(callback_def, "%s)", delegate_parms); +    Printf(callback_def, " {\n"); + +    /* Emit the intermediate class's upcall to the actual class */ + +    String *upcall = NewStringf("(cast(%s)dObject).%s(%s)", classname, symname, imcall_args); + +    if (!is_void) { +      if ((tm = lookupDTypemap(n, "ddirectorout"))) { +	Replaceall(tm, "$dcall", upcall); +	Printf(callback_code, "  return %s;\n", tm); +      } +    } else { +      Printf(callback_code, "  %s;\n", upcall); +    } + +    Printf(callback_code, "}\n"); +    Delete(upcall); + +    if (!ignored_method) { +      if (!is_void) +	Printf(w->code, "jresult = (%s) ", c_ret_type); + +      Printf(w->code, "swig_callback_%s(d_object%s);\n", overloaded_name, dcallback_call_args); + +      if (!is_void) { +	String *jresult_str = NewString("jresult"); +	String *result_str = NewString("c_result"); + +	/* Copy jresult into c_result... */ +	if ((tm = Swig_typemap_lookup("directorout", n, result_str, w))) { +	  Replaceall(tm, "$input", jresult_str); +	  Replaceall(tm, "$result", result_str); +	  Printf(w->code, "%s\n", tm); +	} else { +	  Swig_warning(WARN_TYPEMAP_DIRECTOROUT_UNDEF, input_file, line_number, +		       "Unable to use return type %s used in %s::%s (skipping director method)\n", +		       SwigType_str(returntype, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); +	  output_director = false; +	} + +	Delete(jresult_str); +	Delete(result_str); +      } + +      /* Marshal outputs */ +      for (p = l; p;) { +	if ((tm = Getattr(p, "tmap:directorargout"))) { +	  canThrow(n, "directorargout", p); +	  Replaceall(tm, "$result", "jresult"); +	  Replaceall(tm, "$input", Getattr(p, "emit:directorinput")); +	  Printv(w->code, tm, "\n", NIL); +	  p = Getattr(p, "tmap:directorargout:next"); +	} else { +	  p = nextSibling(p); +	} +      } + +      /* Terminate wrapper code */ +      Printf(w->code, "}\n"); +      if (!is_void) +	Printf(w->code, "return %s;", qualified_return); +    } + +    Printf(w->code, "}"); + +    // We expose virtual protected methods via an extra public inline method which makes a straight call to the wrapped class' method +    String *inline_extra_method = NewString(""); +    if (dirprot_mode() && !is_public(n) && !pure_virtual) { +      Printv(inline_extra_method, declaration, NIL); +      String *extra_method_name = NewStringf("%sSwigPublic", name); +      Replaceall(inline_extra_method, name, extra_method_name); +      Replaceall(inline_extra_method, ";\n", " {\n      "); +      if (!is_void) +	Printf(inline_extra_method, "return "); +      String *methodcall = Swig_method_call(super, l); +      Printv(inline_extra_method, methodcall, ";\n    }\n", NIL); +      Delete(methodcall); +      Delete(extra_method_name); +    } + +    /* emit the director method */ +    if (status == SWIG_OK && output_director) { +      if (!is_void) { +	Replaceall(w->code, "$null", qualified_return); +      } else { +	Replaceall(w->code, "$null", ""); +      } +      if (!ignored_method) +	Printv(director_dcallbacks_code, callback_def, callback_code, NIL); +      if (!Getattr(n, "defaultargs")) { +	Replaceall(w->code, "$symname", symname); +	Wrapper_print(w, f_directors); +	Printv(f_directors_h, declaration, NIL); +	Printv(f_directors_h, inline_extra_method, NIL); +      } +    } + +    if (!ignored_method) { +      // Register the upcall method so that the callback registering code can +      // be written later. + +      // We cannot directly use n here because its »type« attribute does not +      // the full return type any longer after Language::functionHandler has +      // returned. +      String *dp_return_type = lookupDTypemap(n, "dtype"); +      if (dp_return_type) { +	String *dtypeout = Getattr(n, "tmap:dtype:out"); +	if (dtypeout) { +	  // The type in the dtype typemap's out attribute overrides the type +	  // in the typemap itself. +	  dp_return_type = dtypeout; +  	replaceClassname(dp_return_type, returntype); +	} +      } else { +	Swig_warning(WARN_D_TYPEMAP_DTYPE_UNDEF, input_file, line_number, +	  "No dtype typemap defined for %s\n", SwigType_str(returntype, 0)); +	dp_return_type = NewString(""); +      } + +      UpcallData *udata = addUpcallMethod(imclass_dmethod, symname, decl, overloaded_name, dp_return_type, proxy_method_param_list); +      Delete(dp_return_type); + +      // Write the global callback function pointer on the C code. +      String *methid = Getattr(udata, "class_methodidx"); + +      Printf(director_callback_typedefs, "    typedef %s (* SWIG_Callback%s_t)", c_ret_type, methid); +      Printf(director_callback_typedefs, "(void *dobj%s);\n", callback_typedef_parms); +      Printf(director_callback_pointers, "    SWIG_Callback%s_t swig_callback_%s;\n", methid, overloaded_name); + +      // Write the type alias for the callback to the intermediary D module. +      String *proxy_callback_type = NewString(""); +      String *dirClassName = directorClassName(parent); +      Printf(proxy_callback_type, "%s_Callback%s", dirClassName, methid); +      Printf(im_dmodule_code, "alias extern(C) %s function(void*%s) %s;\n", proxy_callback_return_type, delegate_parms, proxy_callback_type); +      Delete(proxy_callback_type); +      Delete(dirClassName); +    } + +    Delete(qualified_return); +    Delete(c_ret_type); +    Delete(declaration); +    Delete(callback_typedef_parms); +    Delete(delegate_parms); +    Delete(proxy_method_param_list); +    Delete(callback_def); +    Delete(callback_code); +    DelWrapper(w); + +    return status; +  } + +  /* --------------------------------------------------------------------------- +   * D::classDirectorConstructor() +   * --------------------------------------------------------------------------- */ +  virtual int classDirectorConstructor(Node *n) { +    Node *parent = parentNode(n); +    String *decl = Getattr(n, "decl");; +    String *supername = Swig_class_name(parent); +    String *dirclassname = directorClassName(parent); +    String *sub = NewString(""); +    Parm *p; +    ParmList *superparms = Getattr(n, "parms"); +    ParmList *parms; +    int argidx = 0; + +    /* Assign arguments to superclass's parameters, if not already done */ +    for (p = superparms; p; p = nextSibling(p)) { +      String *pname = Getattr(p, "name"); + +      if (!pname) { +	pname = NewStringf("arg%d", argidx++); +	Setattr(p, "name", pname); +      } +    } + +    // TODO: Is this copy needed? +    parms = CopyParmList(superparms); + +    if (!Getattr(n, "defaultargs")) { +      /* constructor */ +      { +	String *basetype = Getattr(parent, "classtype"); +	String *target = Swig_method_decl(0, decl, dirclassname, parms, 0); +	String *call = Swig_csuperclass_call(0, basetype, superparms); +	String *classtype = SwigType_namestr(Getattr(n, "name")); + +	Printf(f_directors, "%s::%s : %s, %s {\n", dirclassname, target, call, Getattr(parent, "director:ctor")); +	Printf(f_directors, "  swig_init_callbacks();\n"); +	Printf(f_directors, "}\n\n"); + +	Delete(classtype); +	Delete(target); +	Delete(call); +      } + +      /* constructor header */ +      { +	String *target = Swig_method_decl(0, decl, dirclassname, parms, 1); +	Printf(f_directors_h, "    %s;\n", target); +	Delete(target); +      } +    } + +    Delete(sub); +    Delete(supername); +    Delete(parms); +    Delete(dirclassname); +    return Language::classDirectorConstructor(n); +  } + +  /* --------------------------------------------------------------------------- +   * D::classDirectorDefaultConstructor() +   * --------------------------------------------------------------------------- */ +  virtual int classDirectorDefaultConstructor(Node *n) { +    String *dirclassname = directorClassName(n); +    String *classtype = SwigType_namestr(Getattr(n, "name")); +    Wrapper *w = NewWrapper(); + +    Printf(w->def, "%s::%s() : %s {", dirclassname, dirclassname, Getattr(n, "director:ctor")); +    Printf(w->code, "}\n"); +    Wrapper_print(w, f_directors); + +    Printf(f_directors_h, "    %s();\n", dirclassname); +    DelWrapper(w); +    Delete(classtype); +    Delete(dirclassname); +    return Language::classDirectorDefaultConstructor(n); +  } + +  /* --------------------------------------------------------------------------- +   * D::classDirectorDestructor() +   * --------------------------------------------------------------------------- */ +  virtual int classDirectorDestructor(Node *n) { +    Node *current_class = getCurrentClass(); +    String *dirclassname = directorClassName(current_class); +    Wrapper *w = NewWrapper(); + +    if (Getattr(n, "noexcept")) { +      Printf(f_directors_h, "    virtual ~%s() noexcept;\n", dirclassname); +      Printf(w->def, "%s::~%s() noexcept {\n", dirclassname, dirclassname); +    } else if (Getattr(n, "throw")) { +      Printf(f_directors_h, "    virtual ~%s() throw();\n", dirclassname); +      Printf(w->def, "%s::~%s() throw() {\n", dirclassname, dirclassname); +    } else { +      Printf(f_directors_h, "    virtual ~%s();\n", dirclassname); +      Printf(w->def, "%s::~%s() {\n", dirclassname, dirclassname); +    } + +    Printv(w->code, "}\n", NIL); + +    Wrapper_print(w, f_directors); + +    DelWrapper(w); +    Delete(dirclassname); +    return SWIG_OK; +  } + +  /* --------------------------------------------------------------------------- +   * D::classDirectorEnd() +   * --------------------------------------------------------------------------- */ +  virtual int classDirectorEnd(Node *n) { +    int i; +    String *director_classname = directorClassName(n); + +    Wrapper *w = NewWrapper(); + +    if (Len(director_callback_typedefs) > 0) { +      Printf(f_directors_h, "\n%s", director_callback_typedefs); +    } + +    Printf(f_directors_h, "    void swig_connect_director(void* dobj"); + +    Printf(w->def, "void %s::swig_connect_director(void* dobj", director_classname); +    Printf(w->code, "d_object = dobj;"); + +    for (i = first_class_dmethod; i < curr_class_dmethod; ++i) { +      UpcallData *udata = Getitem(dmethods_seq, i); +      String *methid = Getattr(udata, "class_methodidx"); +      String *overname = Getattr(udata, "overname"); + +      Printf(f_directors_h, ", SWIG_Callback%s_t callback%s", methid, overname); +      Printf(w->def, ", SWIG_Callback%s_t callback_%s", methid, overname); +      Printf(w->code, "swig_callback_%s = callback_%s;\n", overname, overname); +    } + +    Printf(f_directors_h, ");\n"); +    Printf(w->def, ") {"); + +    Printf(f_directors_h, "\nprivate:\n"); +    Printf(f_directors_h, "    void swig_init_callbacks();\n"); +    Printf(f_directors_h, "    void *d_object;\n"); +    if (Len(director_callback_pointers) > 0) { +      Printf(f_directors_h, "%s", director_callback_pointers); +    } +    Printf(f_directors_h, "};\n\n"); +    Printf(w->code, "}\n\n"); + +    Printf(w->code, "void %s::swig_init_callbacks() {\n", director_classname); +    for (i = first_class_dmethod; i < curr_class_dmethod; ++i) { +      UpcallData *udata = Getitem(dmethods_seq, i); +      String *overname = Getattr(udata, "overname"); +      Printf(w->code, "swig_callback_%s = 0;\n", overname); +    } +    Printf(w->code, "}"); + +    Wrapper_print(w, f_directors); + +    DelWrapper(w); + +    return Language::classDirectorEnd(n); +  } + +  /* --------------------------------------------------------------------------- +   * D::classDirectorDisown() +   * --------------------------------------------------------------------------- */ +  virtual int classDirectorDisown(Node *n) { +    (void) n; +    return SWIG_OK; +  } + +  /* --------------------------------------------------------------------------- +   * D::replaceSpecialVariables() +   * --------------------------------------------------------------------------- */ +  virtual void replaceSpecialVariables(String *method, String *tm, Parm *parm) { +    (void)method; +    SwigType *type = Getattr(parm, "type"); + +    // Just assume that this goes to the proxy class, we cannot know. +    replaceClassname(tm, type); +  } + +protected: +  /* --------------------------------------------------------------------------- +   * D::extraDirectorProtectedCPPMethodsRequired() +   * --------------------------------------------------------------------------- */ +  virtual bool extraDirectorProtectedCPPMethodsRequired() const { +    return false; +  } + +private: +  /* --------------------------------------------------------------------------- +   * D::writeImDModuleFunction() +   * +   * Writes a function declaration for the given (C) wrapper function to the +   * intermediary D module. +   * +   * d_name - The name the function in the intermediary D module will get. +   * return type - The return type of the function in the C wrapper. +   * parameters - The parameter list of the C wrapper function. +   * wrapper_function_name - The name of the exported function in the C wrapper +   *                         (usually d_name prefixed by »D_«). +   * --------------------------------------------------------------------------- */ +  void writeImDModuleFunction(const_String_or_char_ptr d_name, +    const_String_or_char_ptr return_type, const_String_or_char_ptr parameters, +    const_String_or_char_ptr wrapper_function_name) { + +    // TODO: Add support for static linking here. +    Printf(im_dmodule_code, "SwigExternC!(%s function%s) %s;\n", return_type, +      parameters, d_name); +    Printv(wrapper_loader_bind_code, wrapper_loader_bind_command, NIL); +    Replaceall(wrapper_loader_bind_code, "$function", d_name); +    Replaceall(wrapper_loader_bind_code, "$symbol", wrapper_function_name); +  } + +  /* --------------------------------------------------------------------------- +   * D::writeProxyClassFunction() +   * +   * Creates a D proxy function for a C++ function in the wrapped class. Used +   * for both static and non-static C++ class functions. +   * +   * The Node must contain two extra attributes. +   *  - "proxyfuncname": The name of the D proxy function. +   *  - "imfuncname": The corresponding function in the intermediary D module. +   * --------------------------------------------------------------------------- */ +  void writeProxyClassFunction(Node *n) { +    SwigType *t = Getattr(n, "type"); +    ParmList *l = Getattr(n, "parms"); +    String *intermediary_function_name = Getattr(n, "imfuncname"); +    String *proxy_function_name = Getattr(n, "proxyfuncname"); +    String *tm; +    Parm *p; +    int i; +    String *imcall = NewString(""); +    String *return_type = NewString(""); +    String *function_code = NewString(""); +    bool setter_flag = false; +    String *pre_code = NewString(""); +    String *post_code = NewString(""); +    String *terminator_code = NewString(""); + +    // Wrappers not wanted for some methods where the parameters cannot be +    // overloaded in D. +    if (Getattr(n, "overload:ignore")) +      return; + +    // Don't generate proxy method for additional explicitcall method used in +    // directors. +    if (GetFlag(n, "explicitcall")) +      return; + +    // RESEARCH: What is this good for? +    if (l) { +      if (SwigType_type(Getattr(l, "type")) == T_VOID) { +	l = nextSibling(l); +      } +    } + +    /* Attach the non-standard typemaps to the parameter list */ +    Swig_typemap_attach_parms("in", l, NULL); +    Swig_typemap_attach_parms("dtype", l, NULL); +    Swig_typemap_attach_parms("din", l, NULL); + +    // Get return types. +    if ((tm = lookupDTypemap(n, "dtype"))) { +      String *dtypeout = Getattr(n, "tmap:dtype:out"); +      if (dtypeout) { +	// The type in the dtype typemap's out attribute overrides the type in +	// the typemap. +	tm = dtypeout; +        replaceClassname(tm, t); +      } +      Printf(return_type, "%s", tm); +    } else { +      Swig_warning(WARN_D_TYPEMAP_DTYPE_UNDEF, input_file, line_number, +	"No dtype typemap defined for %s\n", SwigType_str(t, 0)); +    } + +    if (wrapping_member_flag) { +      // Check if this is a setter method for a public member. +      const String *setter_name = Swig_name_set(getNSpace(), +        Swig_name_member(0, proxy_class_name, variable_name)); + +      if (Cmp(Getattr(n, "sym:name"), setter_name) == 0) { +        setter_flag = true; +      } +    } + +    // Write function modifiers. +    { +      String *modifiers; + +      const String *mods_override = Getattr(n, "feature:d:methodmodifiers"); +      if (mods_override) { +	modifiers = Copy(mods_override); +      } else { +	modifiers = Copy(is_public(n) ? public_string : protected_string); + +	if (Getattr(n, "override")) { +	  Printf(modifiers, " override"); +	} +      } + +      if (is_smart_pointer()) { +	// Smart pointer classes do not mirror the inheritance hierarchy of the +	// underlying pointer type, so no override required. +	Replaceall(modifiers, "override", ""); +      } + +      Chop(modifiers); + +      if (static_flag) { +	Printf(modifiers, " static"); +      } + +      Printf(function_code, "%s ", modifiers); +      Delete(modifiers); +    } + +    // Complete the function declaration up to the parameter list. +    Printf(function_code, "%s %s(", return_type, proxy_function_name); + +    // Write the wrapper function call up to the parameter list. +    Printv(imcall, im_dmodule_fq_name, ".$imfuncname(", NIL); +    if (!static_flag) { +      Printf(imcall, "cast(void*)swigCPtr"); +    } + +    String *proxy_param_types = NewString(""); + +    // Write the parameter list for the proxy function declaration and the +    // wrapper function call. +    emit_mark_varargs(l); +    int gencomma = !static_flag; +    for (i = 0, p = l; p; i++) { +      // Ignored varargs. +      if (checkAttribute(p, "varargs:ignore", "1")) { +	p = nextSibling(p); +	continue; +      } + +      // Ignored parameters. +      if (checkAttribute(p, "tmap:in:numinputs", "0")) { +	p = Getattr(p, "tmap:in:next"); +	continue; +      } + +      // Ignore the 'this' argument for variable wrappers. +      if (!(variable_wrapper_flag && i == 0)) { +	String *param_name = makeParameterName(n, p, i, setter_flag); +	SwigType *pt = Getattr(p, "type"); + +	// Write the wrapper function call argument. +	{ +	  if (gencomma) { +	    Printf(imcall, ", "); +	  } + +	  if ((tm = lookupDTypemap(p, "din", true))) { +	    Replaceall(tm, "$dinput", param_name); +	    String *pre = Getattr(p, "tmap:din:pre"); +	    if (pre) { +	      replaceClassname(pre, pt); +	      Replaceall(pre, "$dinput", param_name); +	      if (Len(pre_code) > 0) +		Printf(pre_code, "\n"); +	      Printv(pre_code, pre, NIL); +	    } +	    String *post = Getattr(p, "tmap:din:post"); +	    if (post) { +	      replaceClassname(post, pt); +	      Replaceall(post, "$dinput", param_name); +	      if (Len(post_code) > 0) +		Printf(post_code, "\n"); +	      Printv(post_code, post, NIL); +	    } +	    String *terminator = Getattr(p, "tmap:din:terminator"); +	    if (terminator) { +	      replaceClassname(terminator, pt); +	      Replaceall(terminator, "$dinput", param_name); +	      if (Len(terminator_code) > 0) +		Insert(terminator_code, 0, "\n"); +	      Insert(terminator_code, 0, terminator); +	    } +	    Printv(imcall, tm, NIL); +	  } else { +	    Swig_warning(WARN_D_TYPEMAP_DIN_UNDEF, input_file, line_number, +	      "No din typemap defined for %s\n", SwigType_str(pt, 0)); +	  } +	} + +	// Write the D proxy function parameter. +	{ +	  String *proxy_type = NewString(""); + +	  if ((tm = lookupDTypemap(p, "dtype"))) { +	    const String *inattributes = Getattr(p, "tmap:dtype:inattributes"); +	    Printf(proxy_type, "%s%s", inattributes ? inattributes : empty_string, tm); +	  } else { +	    Swig_warning(WARN_D_TYPEMAP_DTYPE_UNDEF, input_file, line_number, +	      "No dtype typemap defined for %s\n", SwigType_str(pt, 0)); +	  } + +	  if (gencomma >= 2) { +	    Printf(function_code, ", "); +	    Printf(proxy_param_types, ", "); +	  } +	  gencomma = 2; +	  Printf(function_code, "%s %s", proxy_type, param_name); +	  Append(proxy_param_types, proxy_type); + +	  Delete(proxy_type); +	} + +	Delete(param_name); +      } +      p = Getattr(p, "tmap:in:next"); +    } + +    Printf(imcall, ")"); +    Printf(function_code, ") "); + +    if (d_version > 1 && wrapping_member_flag) { +      Printf(function_code, "@property "); +    } + +    if (wrapMemberFunctionAsDConst(n)) { +      Printf(function_code, "const "); +    } + +    // Lookup the code used to convert the wrapper return value to the proxy +    // function return type. +    if ((tm = lookupDTypemap(n, "dout"))) { +      replaceExcode(n, tm, "dout", n); +      bool is_pre_code = Len(pre_code) > 0; +      bool is_post_code = Len(post_code) > 0; +      bool is_terminator_code = Len(terminator_code) > 0; +      if (is_pre_code || is_post_code || is_terminator_code) { +	if (is_post_code) { +	  Insert(tm, 0, "\n  try "); +	  Printv(tm, " finally {\n", post_code, "\n  }", NIL); +	} else { +	  Insert(tm, 0, "\n  "); +	} +	if (is_pre_code) { +	  Insert(tm, 0, pre_code); +	  Insert(tm, 0, "\n"); +	} +	if (is_terminator_code) { +	  Printv(tm, "\n", terminator_code, NIL); +	} +	Insert(tm, 0, "{"); +	Printv(tm, "}", NIL); +      } +      if (GetFlag(n, "feature:new")) +	Replaceall(tm, "$owner", "true"); +      else +	Replaceall(tm, "$owner", "false"); +      replaceClassname(tm, t); + +      // For director methods: generate code to selectively make a normal +      // polymorphic call or an explicit method call. Needed to prevent infinite +      // recursion when calling director methods. +      Node *explicit_n = Getattr(n, "explicitcallnode"); +      if (explicit_n && Swig_directorclass(getCurrentClass())) { +	String *ex_overloaded_name = getOverloadedName(explicit_n); +	String *ex_intermediary_function_name = Swig_name_member(getNSpace(), proxy_class_name, ex_overloaded_name); + +	String *ex_imcall = Copy(imcall); +	Replaceall(ex_imcall, "$imfuncname", ex_intermediary_function_name); +	Replaceall(imcall, "$imfuncname", intermediary_function_name); + +	String *excode = NewString(""); +	if (!Cmp(return_type, "void")) +	  Printf(excode, "if (swigIsMethodOverridden!(%s delegate(%s), %s function(%s), %s)()) %s; else %s", +	    return_type, proxy_param_types, return_type, proxy_param_types, proxy_function_name, ex_imcall, imcall); +	else +	  Printf(excode, "((swigIsMethodOverridden!(%s delegate(%s), %s function(%s), %s)()) ? %s : %s)", +	    return_type, proxy_param_types, return_type, proxy_param_types, proxy_function_name, ex_imcall, imcall); + +	Clear(imcall); +	Printv(imcall, excode, NIL); +	Delete(ex_overloaded_name); +	Delete(excode); +      } else { +	Replaceall(imcall, "$imfuncname", intermediary_function_name); +      } +      Replaceall(tm, "$imfuncname", intermediary_function_name); +      Replaceall(tm, "$imcall", imcall); +    } else { +      Swig_warning(WARN_D_TYPEMAP_DOUT_UNDEF, input_file, line_number, +	"No dout typemap defined for %s\n", SwigType_str(t, 0)); +    } + +    Delete(proxy_param_types); + +    // The whole function body is now in stored tm (if there was a matching type +    // map, of course), so simply append it to the code buffer. The braces are +    // included in the typemap. +    Printv(function_code, tm, NIL); + +    // Write function code buffer to the class code. +    Printv(proxy_class_body_code, "\n", function_code, "\n", NIL); + +    Delete(pre_code); +    Delete(post_code); +    Delete(terminator_code); +    Delete(function_code); +    Delete(return_type); +    Delete(imcall); +  } + +  /* --------------------------------------------------------------------------- +   * D::writeProxyDModuleFunction() +   * --------------------------------------------------------------------------- */ +  void writeProxyDModuleFunction(Node *n) { +    SwigType *t = Getattr(n, "type"); +    ParmList *l = Getattr(n, "parms"); +    String *tm; +    Parm *p; +    int i; +    String *imcall = NewString(""); +    String *return_type = NewString(""); +    String *function_code = NewString(""); +    int num_arguments = 0; +    String *overloaded_name = getOverloadedName(n); +    String *func_name = NULL; +    String *pre_code = NewString(""); +    String *post_code = NewString(""); +    String *terminator_code = NewString(""); + +    // RESEARCH: What is this good for? +    if (l) { +      if (SwigType_type(Getattr(l, "type")) == T_VOID) { +	l = nextSibling(l); +      } +    } + +    /* Attach the non-standard typemaps to the parameter list */ +    Swig_typemap_attach_parms("dtype", l, NULL); +    Swig_typemap_attach_parms("din", l, NULL); + +    /* Get return types */ +    if ((tm = lookupDTypemap(n, "dtype"))) { +      String *dtypeout = Getattr(n, "tmap:dtype:out"); +      if (dtypeout) { +	// The type in the dtype typemap's out attribute overrides the type in +	// the typemap. +	tm = dtypeout; +	replaceClassname(tm, t); +      } +      Printf(return_type, "%s", tm); +    } else { +      Swig_warning(WARN_D_TYPEMAP_DTYPE_UNDEF, input_file, line_number, +	"No dtype typemap defined for %s\n", SwigType_str(t, 0)); +    } + +    /* Change function name for global variables */ +    if (global_variable_flag) { +      // RESEARCH: Is the Copy() needed here? +      func_name = Copy(variable_name); +    } else { +      func_name = Copy(Getattr(n, "sym:name")); +    } + +    /* Start generating the function */ +    const String *outattributes = Getattr(n, "tmap:dtype:outattributes"); +    if (outattributes) +      Printf(function_code, "  %s\n", outattributes); + +    const String *methodmods = Getattr(n, "feature:d:methodmodifiers"); +    // TODO: Check if is_public(n) could possibly make any sense here +    // (private global functions would be useless anyway?). +    methodmods = methodmods ? methodmods : empty_string; + +    Printf(function_code, "\n%s%s %s(", methodmods, return_type, func_name); +    Printv(imcall, im_dmodule_fq_name, ".", overloaded_name, "(", NIL); + +    /* Get number of required and total arguments */ +    num_arguments = emit_num_arguments(l); + +    int gencomma = 0; + +    /* Output each parameter */ +    for (i = 0, p = l; i < num_arguments; i++) { + +      /* Ignored parameters */ +      while (checkAttribute(p, "tmap:in:numinputs", "0")) { +	p = Getattr(p, "tmap:in:next"); +      } + +      SwigType *pt = Getattr(p, "type"); +      String *param_type = NewString(""); + +      // Get the D parameter type. +      if ((tm = lookupDTypemap(p, "dtype", true))) { +	const String *inattributes = Getattr(p, "tmap:dtype:inattributes"); +	Printf(param_type, "%s%s", inattributes ? inattributes : empty_string, tm); +      } else { +	Swig_warning(WARN_D_TYPEMAP_DTYPE_UNDEF, input_file, line_number, +	  "No dtype typemap defined for %s\n", SwigType_str(pt, 0)); +      } + +      if (gencomma) +	Printf(imcall, ", "); + +      const bool generating_setter = global_variable_flag || wrapping_member_flag; +      String *arg = makeParameterName(n, p, i, generating_setter); + +      // Get the D code to convert the parameter value to the type used in the +      // wrapper D module. +      if ((tm = lookupDTypemap(p, "din", true))) { +	Replaceall(tm, "$dinput", arg); +	String *pre = Getattr(p, "tmap:din:pre"); +	if (pre) { +	  replaceClassname(pre, pt); +	  Replaceall(pre, "$dinput", arg); +	  if (Len(pre_code) > 0) +	    Printf(pre_code, "\n"); +	  Printv(pre_code, pre, NIL); +	} +	String *post = Getattr(p, "tmap:din:post"); +	if (post) { +	  replaceClassname(post, pt); +	  Replaceall(post, "$dinput", arg); +	  if (Len(post_code) > 0) +	    Printf(post_code, "\n"); +	  Printv(post_code, post, NIL); +	} +	String *terminator = Getattr(p, "tmap:din:terminator"); +	if (terminator) { +	  replaceClassname(terminator, pt); +	  Replaceall(terminator, "$dinput", arg); +	  if (Len(terminator_code) > 0) +	    Insert(terminator_code, 0, "\n"); +	  Insert(terminator_code, 0, terminator); +	} +	Printv(imcall, tm, NIL); +      } else { +	Swig_warning(WARN_D_TYPEMAP_DIN_UNDEF, input_file, line_number, +	  "No din typemap defined for %s\n", SwigType_str(pt, 0)); +      } + +      /* Add parameter to module class function */ +      if (gencomma >= 2) +	Printf(function_code, ", "); +      gencomma = 2; +      Printf(function_code, "%s %s", param_type, arg); + +      p = Getattr(p, "tmap:in:next"); +      Delete(arg); +      Delete(param_type); +    } + +    Printf(imcall, ")"); +    Printf(function_code, ") "); + +    if (global_variable_flag && (d_version > 1)) { +      Printf(function_code, "@property "); +    } + +    // Lookup the code used to convert the wrapper return value to the proxy +    // function return type. +    if ((tm = lookupDTypemap(n, "dout"))) { +      replaceExcode(n, tm, "dout", n); +      bool is_pre_code = Len(pre_code) > 0; +      bool is_post_code = Len(post_code) > 0; +      bool is_terminator_code = Len(terminator_code) > 0; +      if (is_pre_code || is_post_code || is_terminator_code) { +	if (is_post_code) { +	  Insert(tm, 0, "\n  try "); +	  Printv(tm, " finally {\n", post_code, "\n  }", NIL); +	} else { +	  Insert(tm, 0, "\n  "); +	} +	if (is_pre_code) { +	  Insert(tm, 0, pre_code); +	  Insert(tm, 0, "\n"); +	} +	if (is_terminator_code) { +	  Printv(tm, "\n", terminator_code, NIL); +	} +	Insert(tm, 0, " {"); +	Printf(tm, "\n}"); +      } +      if (GetFlag(n, "feature:new")) +	Replaceall(tm, "$owner", "true"); +      else +	Replaceall(tm, "$owner", "false"); +      replaceClassname(tm, t); +      Replaceall(tm, "$imfuncname", overloaded_name); +      Replaceall(tm, "$imcall", imcall); +    } else { +      Swig_warning(WARN_D_TYPEMAP_DOUT_UNDEF, input_file, line_number, +	"No dout typemap defined for %s\n", SwigType_str(t, 0)); +    } + +    // The whole function code is now stored in tm (if there was a matching +    // type map, of course), so simply append it to the code buffer. +    Printf(function_code, "%s\n", tm ? (const String *) tm : empty_string); +    Printv(proxyCodeBuffer(getNSpace()), function_code, NIL); + +    Delete(pre_code); +    Delete(post_code); +    Delete(terminator_code); +    Delete(function_code); +    Delete(return_type); +    Delete(imcall); +    Delete(func_name); +  } + +  /* --------------------------------------------------------------------------- +   * D::writeProxyClassAndUpcasts() +   * +   * Collects all the code fragments generated by the handler function while +   * traversing the tree from the proxy_class_* variables and writes the +   * class definition (including any epilogue code) to proxy_class_code. +   * +   * Also writes the upcast function to the wrapper layer when processing a +   * derived class. +   * +   * Inputs: +   *  n – The class node currently processed. +   * --------------------------------------------------------------------------- */ +  void writeProxyClassAndUpcasts(Node *n) { +    SwigType *typemap_lookup_type = Getattr(n, "classtypeobj"); + +    /* +     * Handle inheriting from D and C++ classes. +     */ + +    String *c_classname = Getattr(n, "name"); +    String *c_baseclassname = NULL; +    Node *basenode = NULL; +    String *baseclass = NULL; + +    // Inheritance from pure D classes. +    Node *attributes = NewHash(); +    const String *pure_baseclass = +      lookupCodeTypemap(n, "dbase", typemap_lookup_type, WARN_NONE, attributes); +    bool purebase_replace = GetFlag(attributes, "tmap:dbase:replace") ? true : false; +    bool purebase_notderived = GetFlag(attributes, "tmap:dbase:notderived") ? true : false; +    Delete(attributes); + +    // C++ inheritance. +    if (!purebase_replace) { +      List *baselist = Getattr(n, "bases"); +      if (baselist) { +	Iterator base = First(baselist); +	while (base.item) { +	  if (!GetFlag(base.item, "feature:ignore")) { +	    SwigType *baseclassname = Getattr(base.item, "name"); +	    if (!c_baseclassname) { +	      basenode = base.item; +	      String *name = createProxyName(baseclassname); +	      if (name) { +		c_baseclassname = baseclassname; +		baseclass = name; +	      } +	    } else { +	      /* Warn about multiple inheritance for additional base class(es) */ +	      String *proxyclassname = Getattr(n, "classtypeobj"); +	      Swig_warning(WARN_D_MULTIPLE_INHERITANCE, Getfile(n), Getline(n), +		  "Base %s of class %s ignored: multiple inheritance is not supported in D.\n", SwigType_namestr(baseclassname), SwigType_namestr(proxyclassname)); +	    } +	  } +	  base = Next(base); +	} +      } +    } + +    bool derived = baseclass != NULL; + +    if (derived && purebase_notderived) { +      pure_baseclass = empty_string; +    } +    const String *wanted_base = baseclass ? baseclass : pure_baseclass; + +    if (purebase_replace) { +      wanted_base = pure_baseclass; +      derived = false; +      basenode = NULL; +      baseclass = NULL; +      if (purebase_notderived) { +	Swig_error(Getfile(n), Getline(n), +	  "The dbase typemap for proxy %s must contain just one of the 'replace' or 'notderived' attributes.\n", +	  typemap_lookup_type); +      } +    } else if (baseclass && Len(pure_baseclass) > 0) { +      Swig_warning(WARN_D_MULTIPLE_INHERITANCE, Getfile(n), Getline(n), +	"Warning for %s, base class %s ignored. Multiple inheritance is not supported in D. " +	"Perhaps you need one of the 'replace' or 'notderived' attributes in the dbase typemap?\n", typemap_lookup_type, pure_baseclass); +    } + +    // Add code to do C++ casting to base class (only for classes in an inheritance hierarchy) +    if (derived) { +      writeClassUpcast(n, proxy_class_name, c_classname, c_baseclassname); +    } + +    /* +     * Write needed imports. +     */ +    // If this class is derived from a C++ class, we need to have the D class +    // generated for it in scope. +    if (derived) { +      requireDType(Getattr(basenode, "sym:nspace"), Getattr(basenode, "sym:name")); +    } + +    // Write any custom import statements to the proxy module header. +    const String *imports = lookupCodeTypemap(n, "dimports", typemap_lookup_type, WARN_NONE); +    if (Len(imports) > 0) { +      String* imports_trimmed = Copy(imports); +      Chop(imports_trimmed); +      replaceImportTypeMacros(imports_trimmed); +      Printv(proxy_class_imports, imports_trimmed, "\n", NIL); +      Delete(imports_trimmed); +    } + +    /* +     * Write the proxy class header. +     */ +    // Class modifiers. +    const String *modifiers = +      lookupCodeTypemap(n, "dclassmodifiers", typemap_lookup_type, WARN_D_TYPEMAP_CLASSMOD_UNDEF); + +    // User-defined interfaces. +    const String *interfaces = +      lookupCodeTypemap(n, derived ? "dinterfaces_derived" : "dinterfaces", typemap_lookup_type, WARN_NONE); + +    Printv(proxy_class_code, +      "\n", +      modifiers, +      " $dclassname", +      (*Char(wanted_base) || *Char(interfaces)) ? " : " : "", wanted_base, +      (*Char(wanted_base) && *Char(interfaces)) ? ", " : "", interfaces, " {", +      NIL); + +    /* +     * Write the proxy class body. +     */ +    String* body = NewString(""); + +    // Default class body. +    const String *dbody; +    if (derived) { +      dbody = lookupCodeTypemap(n, "dbody_derived", typemap_lookup_type, WARN_D_TYPEMAP_DBODY_UNDEF); +    } else { +      dbody = lookupCodeTypemap(n, "dbody", typemap_lookup_type, WARN_D_TYPEMAP_DBODY_UNDEF); +    } + +    Printv(body, dbody, NIL); + +    // Destructor and dispose(). +    // If the C++ destructor is accessible (public), it is wrapped by the +    // dispose() method which is also called by the emitted D constructor. If it +    // is not accessible, no D destructor is written and the generated dispose() +    // method throws an exception. +    // This enables C++ classes with protected or private destructors to be used +    // in D as it would be used in C++ (GC finalization is a no-op then because +    // of the empty D destructor) while preventing usage in »scope« variables. +    // The method name for the dispose() method is specified in a typemap +    // attribute called »methodname«. +    const String *tm = NULL; + +    const String *dispose_methodname; +    const String *dispose_methodmodifiers; +    const String *dispose_parameters; +    attributes = NewHash(); +    if (derived) { +      tm = lookupCodeTypemap(n, "ddispose_derived", typemap_lookup_type, WARN_NONE, attributes); +      dispose_methodname = Getattr(attributes, "tmap:ddispose_derived:methodname"); +      dispose_methodmodifiers = Getattr(attributes, "tmap:ddispose_derived:methodmodifiers"); +      dispose_parameters = Getattr(attributes, "tmap:ddispose_derived:parameters"); +    } else { +      tm = lookupCodeTypemap(n, "ddispose", typemap_lookup_type, WARN_NONE, attributes); +      dispose_methodname = Getattr(attributes, "tmap:ddispose:methodname"); +      dispose_methodmodifiers = Getattr(attributes, "tmap:ddispose:methodmodifiers"); +      dispose_parameters = Getattr(attributes, "tmap:ddispose:parameters"); +    } + +    if (tm && *Char(tm)) { +      if (!dispose_methodname) { +	Swig_error(Getfile(n), Getline(n), +	  "No methodname attribute defined in the ddispose%s typemap for %s\n", +	  (derived ? "_derived" : ""), proxy_class_name); +      } +      if (!dispose_methodmodifiers) { +	Swig_error(Getfile(n), Getline(n), +	  "No methodmodifiers attribute defined in ddispose%s typemap for %s.\n", +	  (derived ? "_derived" : ""), proxy_class_name); +      } +      if (!dispose_parameters) +	dispose_parameters = empty_string; +    } + +    if (tm) { +      // Write the destructor if the C++ one is accessible. +      if (*Char(destructor_call)) { +	Printv(body, +	  lookupCodeTypemap(n, "ddestructor", typemap_lookup_type, WARN_NONE), NIL); +      } + +      // Write the dispose() method. +      String *dispose_code = NewString(""); +      Printv(dispose_code, tm, NIL); + +      if (*Char(destructor_call)) { +	Replaceall(dispose_code, "$imcall", destructor_call); +      } else { +	Replaceall(dispose_code, "$imcall", "throw new object.Exception(\"C++ destructor does not have public access\")"); +      } + +      if (*Char(dispose_code)) { +	Printv(body, "\n", NIL); +	const String *methodmods = Getattr(n, "destructmethodmodifiers"); +	if (methodmods) +	  Printv(body, methodmods, NIL); +	else +	  Printv(body, dispose_methodmodifiers, (derived ? " override" : ""), NIL); +	Printv(body, " void ", dispose_methodname, "(", dispose_parameters, ") ", dispose_code, "\n", NIL); +      } +    } + +    if (Swig_directorclass(n)) { +      // If directors are enabled for the current class, generate the +      // director connect helper function which is called from the constructor +      // and write it to the class body. +      writeDirectorConnectProxy(n); +    } + +    // Write all constants and enumerations first to prevent forward reference +    // errors. +    Printv(body, proxy_class_enums_code, NIL); + +    // Write the code generated in other methods to the class body. +    Printv(body, proxy_class_body_code, NIL); + +    // Append extra user D code to the class body. +    Printv(body, +      lookupCodeTypemap(n, "dcode", typemap_lookup_type, WARN_NONE), "\n", NIL); + +    // Write the class body and the curly bracket closing the class definition +    // to the proxy module. +    indentCode(body); +    Replaceall(body, "$dbaseclass", baseclass); + +    Printv(proxy_class_code, body, "\n}\n", NIL); +    Delete(body); + +    // Write the epilogue code if there is any. +    Printv(proxy_class_code, proxy_class_epilogue_code, NIL); +  } + + +  /* --------------------------------------------------------------------------- +   * D::writeClassUpcast() +   * --------------------------------------------------------------------------- */ +  void writeClassUpcast(Node *n, const String* d_class_name, SwigType* c_classname, SwigType* c_baseclassname) { + +    SwigType *smart = Swig_cparse_smartptr(n); +    String *upcast_name = Swig_name_member(getNSpace(), d_class_name, (smart != 0 ? "SmartPtrUpcast" : "Upcast")); +    String *upcast_wrapper_name = Swig_name_wrapper(upcast_name); + +    writeImDModuleFunction(upcast_name, "void*", "(void* objectRef)", +      upcast_wrapper_name); + +    String *classname = SwigType_namestr(c_classname); +    String *baseclassname = SwigType_namestr(c_baseclassname); +    if (smart) { +      String *smartnamestr = SwigType_namestr(smart); +      String *bsmartnamestr = SwigType_namestr(smart); + +      // TODO: SwigType_typedef_resolve_all on a String instead of SwigType is incorrect for templates +      SwigType *rclassname = SwigType_typedef_resolve_all(classname); +      SwigType *rbaseclassname = SwigType_typedef_resolve_all(baseclassname); +      Replaceall(bsmartnamestr, rclassname, rbaseclassname); + +      Printv(upcasts_code, +	"SWIGEXPORT ", bsmartnamestr, " * ", upcast_wrapper_name, +	  "(", smartnamestr, " *objectRef) {\n", +	"    return objectRef ? new ", bsmartnamestr, "(*objectRef) : 0;\n" +	"}\n", +	"\n", NIL); + +      Delete(rbaseclassname); +      Delete(rclassname); +      Delete(bsmartnamestr); +      Delete(smartnamestr); +    } else { +      Printv(upcasts_code, +	"SWIGEXPORT ", baseclassname, " * ", upcast_wrapper_name, +	  "(", classname, " *objectRef) {\n", +	"    return (", baseclassname, " *)objectRef;\n" +	"}\n", +	"\n", NIL); +    } + +    Replaceall(upcasts_code, "$cclass", classname); +    Replaceall(upcasts_code, "$cbaseclass", baseclassname); + +    Delete(baseclassname); +    Delete(classname); +    Delete(upcast_name); +    Delete(upcast_wrapper_name); +    Delete(smart); +  } + +  /* --------------------------------------------------------------------------- +   * D::writeTypeWrapperClass() +   * --------------------------------------------------------------------------- */ +  void writeTypeWrapperClass(String *classname, SwigType *type) { +    Node *n = NewHash(); +    Setfile(n, input_file); +    Setline(n, line_number); + +    assertClassNameValidity(classname); + +    String* imports_target; +    String* code_target; +    File *class_file = NULL; +    if (split_proxy_dmodule) { +      String *filename = NewStringf("%s%s.d", dmodule_directory, classname); +      class_file = NewFile(filename, "w", SWIG_output_files()); +      if (!class_file) { +	FileErrorDisplay(filename); +	Exit(EXIT_FAILURE); +      } +      Append(filenames_list, Copy(filename)); +      Delete(filename); + +      emitBanner(class_file); +      Printf(class_file, "module %s%s;\n", package, classname); +      Printf(class_file, "\nstatic import %s;\n", im_dmodule_fq_name); + +      imports_target = NewString(""); +      code_target = NewString(""); +    } else { +      imports_target = proxyImportsBuffer(0); +      code_target = proxyCodeBuffer(0); +    } + +    // Import statements. +    const String *imports = lookupCodeTypemap(n, "dimports", type, WARN_NONE); +    if (Len(imports) > 0) { +      String *imports_trimmed = Copy(imports); +      Chop(imports_trimmed); +      replaceImportTypeMacros(imports_trimmed); +      Printv(imports_target, imports_trimmed, "\n", NIL); +      Delete(imports_trimmed); +    } + +    // Pure D baseclass and interfaces (no C++ inheritance possible. +    const String *pure_baseclass = lookupCodeTypemap(n, "dbase", type, WARN_NONE); +    const String *pure_interfaces = lookupCodeTypemap(n, "dinterfaces", type, WARN_NONE); + +    // Emit the class. +    Printv(code_target, +      "\n", +      lookupCodeTypemap(n, "dclassmodifiers", type, WARN_D_TYPEMAP_CLASSMOD_UNDEF), +      " $dclassname", +      (*Char(pure_baseclass) || *Char(pure_interfaces)) ? " : " : "", pure_baseclass, +      ((*Char(pure_baseclass)) && *Char(pure_interfaces)) ? ", " : "", pure_interfaces, +      " {", NIL); + +    String* body = NewString(""); +    Printv(body, lookupCodeTypemap(n, "dbody", type, WARN_D_TYPEMAP_DBODY_UNDEF), +      lookupCodeTypemap(n, "dcode", type, WARN_NONE), NIL); +    indentCode(body); +    Printv(code_target, body, "\n}\n", NIL); +    Delete(body); + +    Replaceall(code_target, "$dclassname", classname); + +    if (split_proxy_dmodule) { +      Printv(class_file, imports_target, NIL); +      Delete(imports_target); + +      replaceModuleVariables(code_target); +      Printv(class_file, code_target, NIL); +      Delete(code_target); + +      Delete(class_file); +    } + +    Delete(n); +  } + +  /* --------------------------------------------------------------------------- +   * D::writeDirectorConnectProxy(Node *classNode) +   * +   * Writes the helper method which registers the director callbacks by calling +   * the director connect function from the D side to the proxy class. +   * --------------------------------------------------------------------------- */ +  void writeDirectorConnectProxy(Node* classNode) { +    String *dirClassName = directorClassName(classNode); +    String *connect_name = Swig_name_member(getNSpace(), +      proxy_class_name, "director_connect"); +    Printf(proxy_class_body_code, "\nprivate void swigDirectorConnect() {\n"); + +    int i; +    for (i = first_class_dmethod; i < curr_class_dmethod; ++i) { +      UpcallData *udata = Getitem(dmethods_seq, i); +      String *method = Getattr(udata, "method"); +      String *overloaded_name = Getattr(udata, "overname"); +      String *return_type = Getattr(udata, "return_type"); +      String *param_list = Getattr(udata, "param_list"); +      String *methid = Getattr(udata, "class_methodidx"); +      Printf(proxy_class_body_code, "  %s.%s_Callback%s callback%s;\n", im_dmodule_fq_name, dirClassName, methid, methid); +      Printf(proxy_class_body_code, "  if (swigIsMethodOverridden!(%s delegate(%s), %s function(%s), %s)()) {\n", return_type, param_list, return_type, param_list, method); +      Printf(proxy_class_body_code, "    callback%s = &swigDirectorCallback_%s_%s;\n", methid, proxy_class_name, overloaded_name); +      Printf(proxy_class_body_code, "  }\n\n"); +    } +    Printf(proxy_class_body_code, "  %s.%s(cast(void*)swigCPtr, cast(void*)this", im_dmodule_fq_name, connect_name); +    for (i = first_class_dmethod; i < curr_class_dmethod; ++i) { +      UpcallData *udata = Getitem(dmethods_seq, i); +      String *methid = Getattr(udata, "class_methodidx"); +      Printf(proxy_class_body_code, ", callback%s", methid); +    } +    Printf(proxy_class_body_code, ");\n"); +    Printf(proxy_class_body_code, "}\n"); + +    // Helper function to determine if a method has been overridden in a +    // subclass of the wrapped class. If not, we just pass null to the +    // director_connect_function since the method from the C++ class should +    // be called as usual (see above). +    // Only emit it if the proxy class has at least one method. +    if (first_class_dmethod < curr_class_dmethod) { +      Printf(proxy_class_body_code, "\n"); +      Printf(proxy_class_body_code, "private bool swigIsMethodOverridden(DelegateType, FunctionType, alias fn)() %s{\n", (d_version > 1) ? "const " : ""); +      Printf(proxy_class_body_code, "  DelegateType dg = &fn;\n"); +      Printf(proxy_class_body_code, "  return dg.funcptr != SwigNonVirtualAddressOf!(FunctionType, fn);\n"); +      Printf(proxy_class_body_code, "}\n"); +      Printf(proxy_class_body_code, "\n"); +      Printf(proxy_class_body_code, "private static Function SwigNonVirtualAddressOf(Function, alias fn)() {\n"); +      Printf(proxy_class_body_code, "  return cast(Function) &fn;\n"); +      Printf(proxy_class_body_code, "}\n"); +    } + +    if (Len(director_dcallbacks_code) > 0) { +      Printv(proxy_class_epilogue_code, director_dcallbacks_code, NIL); +    } + +    Delete(director_callback_typedefs); +    director_callback_typedefs = NULL; +    Delete(director_callback_pointers); +    director_callback_pointers = NULL; +    Delete(director_dcallbacks_code); +    director_dcallbacks_code = NULL; +    Delete(dirClassName); +    Delete(connect_name); +  } + +  /* --------------------------------------------------------------------------- +   * D::writeDirectorConnectWrapper() +   * +   * Writes the director connect function and the corresponding declaration to +   * the C++ wrapper respectively the D wrapper. +   * --------------------------------------------------------------------------- */ +  void writeDirectorConnectWrapper(Node *n) { +    if (!Swig_directorclass(n)) +      return; + +    // Output the director connect method. +    String *norm_name = SwigType_namestr(Getattr(n, "name")); +    String *connect_name = Swig_name_member(getNSpace(), +      proxy_class_name, "director_connect"); +    String *dirClassName = directorClassName(n); +    Wrapper *code_wrap; + +    Printv(wrapper_loader_bind_code, wrapper_loader_bind_command, NIL); +    Replaceall(wrapper_loader_bind_code, "$function", connect_name); +    Replaceall(wrapper_loader_bind_code, "$symbol", Swig_name_wrapper(connect_name)); + +    Printf(im_dmodule_code, "extern(C) void function(void* cObject, void* dObject"); + +    code_wrap = NewWrapper(); +    Printf(code_wrap->def, "SWIGEXPORT void D_%s(void *objarg, void *dobj", connect_name); + +    Printf(code_wrap->code, "  %s *obj = (%s *)objarg;\n", norm_name, norm_name); +    Printf(code_wrap->code, "  %s *director = static_cast<%s *>(obj);\n", dirClassName, dirClassName); + +    Printf(code_wrap->code, "  director->swig_connect_director(dobj"); + +    for (int i = first_class_dmethod; i < curr_class_dmethod; ++i) { +      UpcallData *udata = Getitem(dmethods_seq, i); +      String *methid = Getattr(udata, "class_methodidx"); + +      Printf(code_wrap->def, ", %s::SWIG_Callback%s_t callback%s", dirClassName, methid, methid); +      Printf(code_wrap->code, ", callback%s", methid); +      Printf(im_dmodule_code, ", %s_Callback%s callback%s", dirClassName, methid, methid); +    } + +    Printf(code_wrap->def, ") {\n"); +    Printf(code_wrap->code, ");\n"); +    Printf(im_dmodule_code, ") %s;\n", connect_name); +    Printf(code_wrap->code, "}\n"); + +    Wrapper_print(code_wrap, f_wrappers); +    DelWrapper(code_wrap); + +    Delete(connect_name); +    Delete(dirClassName); +  } + +  /* --------------------------------------------------------------------------- +   * D::requireDType() +   * +   * If the given type is not already in scope in the current module, adds an +   * import statement for it. The name is considered relative to the global root +   * package if one is set. +   * +   * This is only used for dependencies created in generated code, user- +   * (i.e. typemap-) specified import statements are handled separately. +   * --------------------------------------------------------------------------- */ +  void requireDType(const String *nspace, const String *symname) { +    String *dmodule = createModuleName(nspace, symname); + +    if (!inProxyModule(dmodule)) { +      String *import = createImportStatement(dmodule); +      Append(import, "\n"); +      if (is_wrapping_class()) { +	addImportStatement(proxy_class_imports, import); +      } else { +	addImportStatement(proxyImportsBuffer(getNSpace()), import); +      } +      Delete(import); +    } +    Delete(dmodule); +  } + +  /* --------------------------------------------------------------------------- +   * D::addImportStatement() +   * +   * Adds the given import statement to the given list of import statements if +   * there is no statement importing that module present yet. +   * --------------------------------------------------------------------------- */ +  void addImportStatement(String *target, const String *import) const { +    char *position = Strstr(target, import); +    if (position) { +      // If the import statement has been found in the target string, we have to +      // check if the previous import was static, which would lead to problems +      // if this import is not. +      // Thus, we check if the seven characters in front of the occurrence are +      // »static «. If the import string passed is also static, the checks fail +      // even if the found statement is also static because the last seven +      // characters would be part of the previous import statement then. + +      if (position - Char(target) < 7) { +	return; +      } +      if (strncmp(position - 7, "static ", 7)) { +	return; +      } +    } + +    Printv(target, import, NIL); +  } + +  /* --------------------------------------------------------------------------- +   * D::createImportStatement() +   * +   * Creates a string containing an import statement for the given module. +   * --------------------------------------------------------------------------- */ +  String *createImportStatement(const String *dmodule_name, +    bool static_import = true) const { + +    if (static_import) { +      return NewStringf("static import %s%s;", package, dmodule_name); +    } else { +      return NewStringf("import %s%s;", package, dmodule_name); +    } +  } + +  /* --------------------------------------------------------------------------- +   * D::inProxyModule() +   * +   * Determines if the specified proxy type is declared in the currently +   * processed proxy D module. +   * +   * This function is used to determine if fully qualified type names have to +   * be used (package, module and type name). If the split proxy mode is not +   * used, this solely depends on whether the type is in the current namespace. +   * --------------------------------------------------------------------------- */ +  bool inProxyModule(const String *type_name) const { +    if (!split_proxy_dmodule) { +      String *nspace = createOuterNamespaceNames(type_name); + +      // Check if strings are either both null (no namespace) or are both +      // non-null and have the same contents. Cannot use Strcmp for this +      // directly because of its strange way of handling the case where only +      // one argument is 0 ("<"). +      bool result = !nspace && !getNSpace(); +      if (nspace && getNSpace()) +	result = (Strcmp(nspace, getNSpace()) == 0); + +      Delete(nspace); +      return result; +    } + +    if (!is_wrapping_class()) { +      return false; +    } + +    return (Strcmp(proxy_class_qname, type_name) == 0); +  } + +  /* --------------------------------------------------------------------------- +   * D::addUpcallMethod() +   * +   * Adds new director upcall signature. +   * --------------------------------------------------------------------------- */ +  UpcallData *addUpcallMethod(String *imclass_method, String *class_method, +    String *decl, String *overloaded_name, String *return_type, String *param_list) { + +    String *key = NewStringf("%s|%s", imclass_method, decl); + +    ++curr_class_dmethod; + +    String *class_methodidx = NewStringf("%d", n_dmethods - first_class_dmethod); +    n_dmethods++; + +    Hash *new_udata = NewHash(); +    Append(dmethods_seq, new_udata); +    Setattr(dmethods_table, key, new_udata); + +    Setattr(new_udata, "method", Copy(class_method)); +    Setattr(new_udata, "class_methodidx", class_methodidx); +    Setattr(new_udata, "decl", Copy(decl)); +    Setattr(new_udata, "overname", Copy(overloaded_name)); +    Setattr(new_udata, "return_type", Copy(return_type)); +    Setattr(new_udata, "param_list", Copy(param_list)); + +    Delete(key); +    return new_udata; +  } + +  /* --------------------------------------------------------------------------- +   * D::assertClassNameValidity() +   * --------------------------------------------------------------------------- */ +  void assertClassNameValidity(const String* class_name) const { +    // TODO: With nspace support, there could arise problems also when not in +    // split proxy mode, warnings for these should be added. +    if (split_proxy_dmodule) { +      if (Cmp(class_name, im_dmodule_name) == 0) { +	Swig_error(input_file, line_number, +	  "Class name cannot be equal to intermediary D module name: %s\n", +	  class_name); +	Exit(EXIT_FAILURE); +      } + +      String *nspace = getNSpace(); +      if (nspace) { +	// Check the root package/outermost namespace (a class A in module +	// A.B leads to problems if another module A.C is also imported) +	if (Len(package) > 0) { +	  String *dotless_package = NewStringWithSize(package, Len(package) - 1); +	  if (Cmp(class_name, dotless_package) == 0) { +	    Swig_error(input_file, line_number, +	      "Class name cannot be the same as the root package it is in: %s\n", +	      class_name); +	    Exit(EXIT_FAILURE); +	  } +	  Delete(dotless_package); +	} else { +	  String *outer = createFirstNamespaceName(nspace); +	  if (Cmp(class_name, outer) == 0) { +	    Swig_error(input_file, line_number, +	      "Class name cannot be the same as the outermost namespace it is in: %s\n", +	      class_name); +	    Exit(EXIT_FAILURE); +	  } +	  Delete(outer); +	} + +	// … and the innermost one (because of the conflict with the main proxy +	// module named like the namespace). +	String *inner = createLastNamespaceName(nspace); +	if (Cmp(class_name, inner) == 0) { +	  Swig_error(input_file, line_number, +	    "Class name cannot be the same as the innermost namespace it is in: %s\n", +	    class_name); +	  Exit(EXIT_FAILURE); +	} +	Delete(inner); +      } else { +	if (Cmp(class_name, proxy_dmodule_name) == 0) { +	  Swig_error(input_file, line_number, +	    "Class name cannot be equal to proxy D module name: %s\n", +	    class_name); +	  Exit(EXIT_FAILURE); +	} +      } +    } +  } + +  /* --------------------------------------------------------------------------- +   * D::getPrimitiveDptype() +   * +   * Returns the D proxy type for the passed type if it is a primitive type in +   * both C and D. +   * --------------------------------------------------------------------------- */ +  String *getPrimitiveDptype(Node *node, SwigType *type) { +    SwigType *stripped_type = SwigType_typedef_resolve_all(type); + +    // A reference can only be the »outermost element« of a type. +    bool mutable_ref = false; +    if (SwigType_isreference(stripped_type)) { +      SwigType_del_reference(stripped_type); + +      if (SwigType_isconst(stripped_type)) { +	SwigType_del_qualifier(stripped_type); +      } else { +	mutable_ref = true; +      } +    } + +    // Strip all the pointers from the type. +    int indirection_count = 0; +    while (SwigType_ispointer(stripped_type)) { +      ++indirection_count; +      SwigType_del_pointer(stripped_type); +    } + +    // Now that we got rid of the pointers, see if we are dealing with a +    // primitive type. +    String *dtype = 0; +    if (SwigType_isfunction(stripped_type) && indirection_count > 0) { +      // type was a function pointer, split it up. +      SwigType_add_pointer(stripped_type); +      --indirection_count; + +      SwigType *return_type = Copy(stripped_type); +      SwigType *params_type = SwigType_functionpointer_decompose(return_type); +      String *return_dtype = getPrimitiveDptype(node, return_type); +      Delete(return_type); +      if (!return_dtype) { +	return 0; +      } + +      List *parms = SwigType_parmlist(params_type); +      List *param_dtypes = NewList(); +      for (Iterator it = First(parms); it.item; it = Next(it)) { +	String *current_dtype = getPrimitiveDptype(node, it.item); +	if (Cmp(current_dtype, "void") == 0) { +	  // void somefunc(void) is legal syntax in C, but not in D, so simply +	  // skip the void parameter. +	  Delete(current_dtype); +	  continue; +	} +	if (!current_dtype) { +	  Delete(return_dtype); +	  Delete(param_dtypes); +	  return 0; +	} +	Append(param_dtypes, current_dtype); +      } + +      String *param_list = NewString(""); +      { +	bool gen_comma = false; +	for (Iterator it = First(param_dtypes); it.item; it = Next(it)) { +	  if (gen_comma) { +	    Append(param_list, ", "); +	  } +	  Append(param_list, it.item); +	  Delete(it.item); +	  gen_comma = true; +	} +      } + +      dtype = NewStringf("%s.SwigExternC!(%s function(%s))", im_dmodule_fq_name, +        return_dtype, param_list); +      Delete(param_list); +      Delete(param_dtypes); +      Delete(return_dtype); +    } else { +      Hash *attributes = NewHash(); +      const String *tm = +	lookupCodeTypemap(node, "dtype", stripped_type, WARN_NONE, attributes); +      if(!GetFlag(attributes, "tmap:dtype:cprimitive")) { +	dtype = 0; +      } else { +	dtype = Copy(tm); + +	// We need to call replaceClassname here with the stripped type to avoid +	// $dclassname in the enum typemaps being replaced later with the full +	// type. +	replaceClassname(dtype, stripped_type); +      } +      Delete(attributes); +    } +    Delete(stripped_type); + +    if (!dtype) { +      // The type passed is no primitive type. +      return 0; +    } + +    // The type is ultimately a primitive type, now append the right number of +    // indirection levels (pointers). +    for (int i = 0; i < indirection_count; ++i) { +      Append(dtype, "*"); +    } + +    // Add a level of indirection for a mutable reference since it is wrapped +    // as a pointer. +    if (mutable_ref) { +      Append(dtype, "*"); +    } + +    return dtype; +  } + +  /* --------------------------------------------------------------------------- +   * D::lookupCodeTypemap() +   * +   * Looks up a D code fragment for generating the wrapper class for the given +   * type. +   * +   * n - for input only and must contain info for Getfile(n) and Getline(n) to work +   * tmap_method - typemap method name +   * type - typemap type to lookup +   * warning - warning number to issue if no typemaps found +   * typemap_attributes - the typemap attributes are attached to this node and will +   *   also be used for temporary storage if non null +   * return is never NULL, unlike Swig_typemap_lookup() +   * --------------------------------------------------------------------------- */ +  const String *lookupCodeTypemap(Node *n, const_String_or_char_ptr tmap_method, +    SwigType *type, int warning, Node *typemap_attributes = 0) const { + +    Node *node = !typemap_attributes ? NewHash() : typemap_attributes; +    Setattr(node, "type", type); +    Setfile(node, Getfile(n)); +    Setline(node, Getline(n)); +    const String *tm = Swig_typemap_lookup(tmap_method, node, "", 0); +    if (!tm) { +      tm = empty_string; +      if (warning != WARN_NONE) { +	Swig_warning(warning, Getfile(n), Getline(n), +	  "No %s typemap defined for %s\n", tmap_method, SwigType_str(type, 0)); +      } +    } +    if (!typemap_attributes) { +      Delete(node); +    } + +    return tm; +  } + +  /* --------------------------------------------------------------------------- +   * D::lookupDTypemap() +   * +   * Looks up a D typemap for the given node, replacing D-specific special +   * variables as needed. +   * +   * The method parameter specifies the typemap method to use. If attached is +   * true, the value is just fetched from the tmap:<method> node attribute, +   * Swig_typemap_lookup is used otherwise. +   * --------------------------------------------------------------------------- */ +  String *lookupDTypemap(Node *n, const_String_or_char_ptr method, bool attached = false) { +    String *result = 0; + +    if (attached) { +      String *attr_name = NewStringf("tmap:%s", method); +      result = Copy(Getattr(n, attr_name)); +      Delete(attr_name); +    } else { +      // FIXME: As a workaround for a bug so far only surfacing in the +      // smart_pointer_const_overload test case, remove the nativepointer +      // typemap attribute since it seems to be already there from a dout +      // typemap of a different type in that test. +      String *np_key = NewStringf("tmap:%s:nativepointer", method); +      Delattr(n, np_key); +      Delete(np_key); + +      result = Swig_typemap_lookup(method, n, "", 0); +    } + +    if (!result) { +      return 0; +    } + +    // Check if the passed node actually has type information attached. This +    // is not the case e.g. in constructorWrapper. +    SwigType *type = Getattr(n, "type"); +    if (type) { +      String *np_key = NewStringf("tmap:%s:nativepointer", method); +      String *np_value = Getattr(n, np_key); +      Delete(np_key); +      String *dtype; +      if (np_value && (dtype = getPrimitiveDptype(n, type))) { +        // If the typemap in question has a »nativepointer« attribute and we +        // are dealing with a primitive type, use it instead. +        result = Copy(np_value); +        Replaceall(result, "$dtype", dtype); +      } + +      replaceClassname(result, type); +    } + +    return result; +  } + +  /* --------------------------------------------------------------------------- +   * D::replaceClassname() +   * +   * Replaces the special variable $dclassname with the proxy class name for +   * classes/structs/unions SWIG knows about. Also substitutes the enumeration +   * name for non-anonymous enums. Otherwise, $classname is replaced with a +   * $descriptor(type)-like name. +   * +   * $*dclassname and $&classname work like with descriptors (see manual section +   * 10.4.3), they remove a prointer from respectively add a pointer to the type. +   * +   * Inputs: +   *   tm - String to perform the substitution at (will usually come from a +   *        typemap. +   *   pt - The type to substitute for the variables. +   * Outputs: +   *   tm - String with the variables substituted. +   * Return: +   *   substitution_performed - flag indicating if a substitution was performed +   * --------------------------------------------------------------------------- */ +  bool replaceClassname(String *tm, SwigType *pt) { +    bool substitution_performed = false; +    SwigType *type = Copy(SwigType_typedef_resolve_all(pt)); +    SwigType *strippedtype = SwigType_strip_qualifiers(type); + +    if (Strstr(tm, "$dclassname")) { +      SwigType *classnametype = Copy(strippedtype); +      replaceClassnameVariable(tm, "$dclassname", classnametype); +      substitution_performed = true; +      Delete(classnametype); +    } +    if (Strstr(tm, "$*dclassname")) { +      SwigType *classnametype = Copy(strippedtype); +      Delete(SwigType_pop(classnametype)); +      replaceClassnameVariable(tm, "$*dclassname", classnametype); +      substitution_performed = true; +      Delete(classnametype); +    } +    if (Strstr(tm, "$&dclassname")) { +      SwigType *classnametype = Copy(strippedtype); +      SwigType_add_pointer(classnametype); +      replaceClassnameVariable(tm, "$&dclassname", classnametype); +      substitution_performed = true; +      Delete(classnametype); +    } + +    Delete(strippedtype); +    Delete(type); + +    return substitution_performed; +  } + +  /* --------------------------------------------------------------------------- +   * D::replaceClassnameVariable() +   * +   * See D::replaceClassname(). +   * --------------------------------------------------------------------------- */ +  void replaceClassnameVariable(String *target, const char *variable, SwigType *type) { +    // TODO: Fix const-correctness of methods called in here and make type const. + +    // We make use of the fact that this function is called at least once for +    // every type encountered which is written to a separate file, which allows +    // us to handle imports here. +    // When working in split proxy module mode, each generated proxy class/enum +    // is written to a separate module. This requires us to add a corresponding +    // import when a type is used in another generated module. If we are not +    // working in split proxy module mode, this is not relevant and the +    // generated module name is discarded. +    String *type_name; + +    if (SwigType_isenum(type)) { +      // RESEARCH: Make sure that we really cannot get here for anonymous enums. +      Node *n = enumLookup(type); +      if (n) { +	String *enum_name = Getattr(n, "sym:name"); + +	Node *p = parentNode(n); +	if (p && !Strcmp(nodeType(p), "class")) { +	  // This is a nested enum. +	  String *parent_name = Getattr(p, "sym:name"); +	  String *nspace = Getattr(p, "sym:nspace"); + +	  // An enum nested in a class is not written to a separate module (this +	  // would not even be possible in D), so just import the parent. +	  requireDType(nspace, parent_name); + +	  String *module = createModuleName(nspace, parent_name); +	  if (inProxyModule(module)) { +	    type_name = NewStringf("%s.%s", parent_name, enum_name); +	  } else { +	    type_name = NewStringf("%s%s.%s.%s", package, module, parent_name, enum_name); +	  } +	} else { +	  // A non-nested enum is written to a separate module, import it. +	  String *nspace = Getattr(n, "sym:nspace"); +	  requireDType(nspace, enum_name); + +	  String *module = createModuleName(nspace, enum_name); +	  if (inProxyModule(module)) { +	    type_name = Copy(enum_name); +	  } else { +	    type_name = NewStringf("%s%s.%s", package, module, enum_name); +	  } +	} +      } else { +	type_name = NewStringf("int"); +      } +    } else { +      Node *n = classLookup(type); +      if (n) { +	String *class_name = Getattr(n, "sym:name"); +	String *nspace = Getattr(n, "sym:nspace"); +	requireDType(nspace, class_name); + +	String *module = createModuleName(nspace, class_name); +	if (inProxyModule(module)) { +	  type_name = Copy(class_name); +	} else { +	  type_name = NewStringf("%s%s.%s", package, module, class_name); +	} +        Delete(module); +      } else { +	// SWIG does not know anything about the type (after resolving typedefs). +	// Just mangle the type name string like $descriptor(type) would do. +	String *descriptor = NewStringf("SWIGTYPE%s", SwigType_manglestr(type)); +	requireDType(NULL, descriptor); + +	String *module = createModuleName(NULL, descriptor); +	if (inProxyModule(module)) { +	  type_name = Copy(descriptor); +	} else { +	  type_name = NewStringf("%s%s.%s", package, module, descriptor); +	} +	Delete(module); + +	// Add to hash table so that a type wrapper class can be created later. +	Setattr(unknown_types, descriptor, type); + +	Delete(descriptor); +      } +    } + +    Replaceall(target, variable, type_name); +    Delete(type_name); +  } + +  /* --------------------------------------------------------------------------- +   * D::createModuleName() +   * +   * Returns a string holding the name of the module to import to bring the +   * given type in scope. +   * --------------------------------------------------------------------------- */ +  String *createModuleName(const String *nspace, const String *type_name) const { +    String *module; +    if (nspace) { +      module = NewStringf("%s.", nspace); +      if (split_proxy_dmodule) { +	Printv(module, type_name, NIL); +      } else { +	String *inner = createLastNamespaceName(nspace); +	Printv(module, inner, NIL); +	Delete(inner); +      } +    } else { +      if (split_proxy_dmodule) { +	module = Copy(type_name); +      } else { +	module = Copy(proxy_dmodule_name); +      } +    } +    return module; +  } + +  /* --------------------------------------------------------------------------- +   * D::replaceModuleVariables() +   * +   * Replaces the $imdmodule and $module variables with their values in the +   * target string. +   * --------------------------------------------------------------------------- */ +  void replaceModuleVariables(String *target) const { +    Replaceall(target, "$imdmodule", im_dmodule_fq_name); +    Replaceall(target, "$module", proxy_dmodule_name); +  } + +  /* --------------------------------------------------------------------------- +   * D::replaceExcode() +   * +   * If a C++ method can throw a exception, additional code is added to the +   * proxy method to check if an exception is pending so that it can be +   * rethrown on the D side. +   * +   * This method replaces the $excode variable with the exception handling code +   * in the excode typemap attribute if it »canthrow« an exception. +   * --------------------------------------------------------------------------- */ +  void replaceExcode(Node *n, String *code, const String *typemap, Node *parameter) const { +    String *excode_attribute = NewStringf("tmap:%s:excode", typemap); +    String *excode = Getattr(parameter, excode_attribute); +    if (Getattr(n, "d:canthrow")) { +      int count = Replaceall(code, "$excode", excode); +      if (count < 1 || !excode) { +	Swig_warning(WARN_D_EXCODE_MISSING, input_file, line_number, +	  "D exception may not be thrown – no $excode or excode attribute in '%s' typemap.\n", +	  typemap); +      } +    } else { +      Replaceall(code, "$excode", ""); +    } +    Delete(excode_attribute); +  } + +  /* --------------------------------------------------------------------------- +   * D::replaceImportTypeMacros() +   * +   * Replaces the $importtype(SomeDClass) macro with an import statement if it +   * is required to get SomeDClass in scope for the currently generated proxy +   * D module. +   * --------------------------------------------------------------------------- */ +  void replaceImportTypeMacros(String *target) const { +    // Code from replace_embedded_typemap. +    char *start = 0; +    while ((start = Strstr(target, "$importtype("))) { +      char *end = 0; +      char *param_start = 0; +      char *param_end = 0; +      int level = 0; +      char *c = start; +      while (*c) { +	if (*c == '(') { +	  if (level == 0) { +	    param_start = c + 1; +	  } +	  level++; +	} +	if (*c == ')') { +	  level--; +	  if (level == 0) { +	    param_end = c; +	    end = c + 1; +	    break; +	  } +	} +	c++; +      } + +      if (end) { +	String *current_macro = NewStringWithSize(start, (int)(end - start)); +	String *current_param = NewStringWithSize(param_start, (int)(param_end - param_start)); + + +	if (inProxyModule(current_param)) { +	  Replace(target, current_macro, "", DOH_REPLACE_ANY); +	} else { +	  String *import = createImportStatement(current_param, false); +	  Replace(target, current_macro, import, DOH_REPLACE_ANY); +	  Delete(import); +	} + +	Delete(current_param); +	Delete(current_macro); +      } else { +	String *current_macro = NewStringWithSize(start, (int)(c - start)); +	Swig_error(Getfile(target), Getline(target), "Syntax error in: %s\n", current_macro); +	Replace(target, current_macro, "<error in $importtype macro>", DOH_REPLACE_ANY); +	Delete(current_macro); +      } +    } +  } + +  /* --------------------------------------------------------------------------- +   * D::getOverloadedName() +   * --------------------------------------------------------------------------- */ +  String *getOverloadedName(Node *n) const { +    // A void* parameter is used for all wrapped classes in the wrapper code. +    // Thus, the wrapper function names for overloaded functions are postfixed +    // with a counter string to make them unique. +    String *overloaded_name = Copy(Getattr(n, "sym:name")); + +    if (Getattr(n, "sym:overloaded")) { +      Append(overloaded_name, Getattr(n, "sym:overname")); +    } + +    return overloaded_name; +  } + +  /* --------------------------------------------------------------------------- +   * D::createProxyName() +   * +   * Returns the D class name if a type corresponds to something wrapped with a +   * proxy class, NULL otherwise. +   * --------------------------------------------------------------------------- */ +  String *createProxyName(SwigType *t) { +    String *proxyname = NULL; +    Node *n = classLookup(t); +    if (n) { +      String *nspace = Getattr(n, "sym:nspace"); +      String *symname = Getattr(n, "sym:name"); + +      String *module = createModuleName(nspace, symname); +      if (inProxyModule(module)) { +	proxyname = Copy(symname); +      } else { +	proxyname = NewStringf("%s%s.%s", package, module, symname); +      } +    } +    return proxyname; +  } + +  String *makeParameterName(Node *n, Parm *p, int arg_num, bool setter) const { +    String *arg = Language::makeParameterName(n, p, arg_num, setter); + +    if (split_proxy_dmodule && Strncmp(arg, package, Len(arg)) == 0) { +      // If we are in split proxy mode and the argument is named like the target +      // package, we append an underscore to its name to avoid clashes. +      Append(arg, "_"); +    } + +    return arg; +  } + +  /* --------------------------------------------------------------------------- +   * D::canThrow() +   * +   * Determines whether the code in the typemap can throw a D exception. +   * If so, note it for later when excodeSubstitute() is called. +   * --------------------------------------------------------------------------- */ +  void canThrow(Node *n, const String *typemap, Node *parameter) const { +    String *canthrow_attribute = NewStringf("tmap:%s:canthrow", typemap); +    String *canthrow = Getattr(parameter, canthrow_attribute); +    if (canthrow) +      Setattr(n, "d:canthrow", "1"); +    Delete(canthrow_attribute); +  } + +  /* --------------------------------------------------------------------------- +   * D::wrapMemberFunctionAsDConst() +   * +   * Determines whether the member function represented by the passed node is +   * wrapped as D »const« or not. +   * --------------------------------------------------------------------------- */ +  bool wrapMemberFunctionAsDConst(Node *n) const { +    if (d_version == 1) return false; +    if (static_flag) return false; // Never emit »const« for static member functions. +    return GetFlag(n, "memberget") || SwigType_isconst(Getattr(n, "decl")); +  } + +  /* --------------------------------------------------------------------------- +   * D::areAllOverloadsOverridden() +   * +   * Determines whether the class the passed function node belongs to overrides +   * all the overlaods for the passed function node defined somewhere up the +   * inheritance hierarchy. +   * --------------------------------------------------------------------------- */ +  bool areAllOverloadsOverridden(Node *n) const { +    List *base_list = Getattr(parentNode(n), "bases"); +    if (!base_list) { +      // If the class which contains n is not derived from any other class, +      // there cannot be any not-overridden overloads. +      return true; +    } + +    // In case of multiple base classes, skip to the one which has not been +    // ignored. +    // RESEARCH: Also emit a warning in case of multiple inheritance here? +    Iterator it = First(base_list); +    while (it.item && GetFlag(it.item, "feature:ignore")) { +      it = Next(it); +    } +    Node *base_class = it.item; + +    if (!base_class) { +      // If all base classes have been ignored, there cannot be one either. +      return true; +    } + +    // We try to find at least a single overload which exists in the base class +    // so we can progress up the inheritance hierarchy even if there have been +    // new overloads introduced after the topmost class. +    Node *base_function = NULL; +    String *symname = Getattr(n, "sym:name"); +    if (symname) { +      for (Node *tmp = firstChild(base_class); tmp; tmp = nextSibling(tmp)) { +	String *child_symname = Getattr(tmp, "sym:name"); +	if (child_symname && (Strcmp(child_symname, symname) == 0)) { +	  base_function = tmp; +	  break; +	} +      } +    } + +    if (!base_function) { +      // If there is no overload which also exists in the super class, there +      // cannot be any base class overloads not overridden. +      return true; +    } + +    size_t base_overload_count = 0; +    for (Node *tmp = firstSibling(base_function); tmp; tmp = Getattr(tmp, "sym:nextSibling")) { +      if (is_protected(base_function) && +	  !(Swig_director_mode() && Swig_director_protected_mode() && Swig_all_protected_mode())) { +	// If the base class function is »protected« and were are not in +	// director mode, it is not emitted to the base class and thus we do +	// not count it. Otherwise, we would run into issues if the visibility +	// of some functions was changed from protected to public in a child +	// class with the using directive. +	continue; +      } +      ++base_overload_count; +    } + +    return ((base_overload_count <= overridingOverloadCount(n)) && +      areAllOverloadsOverridden(base_function)); +  } + +  /* --------------------------------------------------------------------------- +   * D::overridingOverloadCount() +   * +   * Given a member function node, this function counts how many of the +   * overloads of the function (including itself) override a function in the +   * base class. +   * --------------------------------------------------------------------------- */ +  size_t overridingOverloadCount(Node *n) const { +    size_t result = 0; + +    Node *tmp = firstSibling(n); +    do { +      // KLUDGE: We also have to count the function if the access attribute is +      // not present, since this means that it has been promoted into another +      // protection level in the base class with the C++ »using« directive, and +      // is thus taken into account when counting the base class overloads, even +      // if it is not marked as »override« by the SWIG parser. +      if (Getattr(n, "override") || !Getattr(n, "access")) { +	++result; +      } +    } while((tmp = Getattr(tmp, "sym:nextSibling"))); + +    return result; +  } + +  /* --------------------------------------------------------------------------- +   * D::firstSibling() +   * +   * Returns the first sibling of the passed node. +   * --------------------------------------------------------------------------- */ +  Node *firstSibling(Node *n) const { +    Node *result = n; +    while (Node *tmp = Getattr(result, "sym:previousSibling")) { +      result = tmp; +    } +    return result; +  } + +  /* --------------------------------------------------------------------------- +   * D::indentCode() +   * +   * Helper function to indent a code (string) by one level. +   * --------------------------------------------------------------------------- */ +  void indentCode(String* code) const { +    Replaceall(code, "\n", "\n  "); +    Replaceall(code, "  \n", "\n"); +    Chop(code); +  } + +  /* --------------------------------------------------------------------------- +   * D::emitBanner() +   * --------------------------------------------------------------------------- */ +  void emitBanner(File *f) const { +    Printf(f, "/* ----------------------------------------------------------------------------\n"); +    Swig_banner_target_lang(f, " *"); +    Printf(f, " * ----------------------------------------------------------------------------- */\n\n"); +  } + +  /* --------------------------------------------------------------------------- +   * D::outputDirectory() +   * +   * Returns the directory to write the D modules for the given namespace to and +   * and creates the subdirectory if it doesn't exist. +   * --------------------------------------------------------------------------- */ +  String *outputDirectory(String *nspace) { +    String *output_directory = Copy(dmodule_directory); +    if (nspace) { +      String *nspace_subdirectory = Copy(nspace); +      Replaceall(nspace_subdirectory, ".", SWIG_FILE_DELIMITER); +      String *newdir_error = Swig_new_subdirectory(output_directory, nspace_subdirectory); +      if (newdir_error) { +	Printf(stderr, "%s\n", newdir_error); +	Delete(newdir_error); +	Exit(EXIT_FAILURE); +      } +      Printv(output_directory, nspace_subdirectory, SWIG_FILE_DELIMITER, 0); +      Delete(nspace_subdirectory); +    } +    return output_directory; +  } + +  /* --------------------------------------------------------------------------- +   * D::proxyCodeBuffer() +   * +   * Returns the buffer to write proxy code for the given namespace to. +   * --------------------------------------------------------------------------- */ +  String *proxyCodeBuffer(String *nspace) { +    if (!nspace) { +      return proxy_dmodule_code; +    } + +    Hash *hash = Getattr(nspace_proxy_dmodules, nspace); +    if (!hash) { +      hash = NewHash(); +      Setattr(hash, "code", NewString("")); +      Setattr(hash, "imports", NewString("")); +      Setattr(nspace_proxy_dmodules, nspace, hash); +    } +    return Getattr(hash, "code"); +  } + +  /* --------------------------------------------------------------------------- +   * D::proxyCodeBuffer() +   * +   * Returns the buffer to write imports for the proxy code for the given +   * namespace to. +   * --------------------------------------------------------------------------- */ +  String *proxyImportsBuffer(String *nspace) { +    if (!nspace) { +      return proxy_dmodule_imports; +    } + +    Hash *hash = Getattr(nspace_proxy_dmodules, nspace); +    if (!hash) { +      hash = NewHash(); +      Setattr(hash, "code", NewString("")); +      Setattr(hash, "imports", NewString("")); +      Setattr(nspace_proxy_dmodules, nspace, hash); +    } +    return Getattr(hash, "imports"); +  } + +  /* --------------------------------------------------------------------------- +   * D::createFirstNamespaceName() +   * +   * Returns a new string containing the name of the outermost namespace, e.g. +   * »A« for the argument »A.B.C«. +   * --------------------------------------------------------------------------- */ +  String *createFirstNamespaceName(const String *nspace) const { +    char *tmp = Char(nspace); +    char *c = tmp; +    char *co = 0; +    if (!strstr(c, ".")) +      return 0; + +    co = c + Len(nspace); + +    while (*c && (c != co)) { +      if (*c == '.') { +	break; +      } +      c++; +    } +    if (!*c || (c == tmp)) { +      return NULL; +    } +    return NewStringWithSize(tmp, (int)(c - tmp)); +  } + +  /* --------------------------------------------------------------------------- +   * D::createLastNamespaceName() +   * +   * Returns a new string containing the name of the innermost namespace, e.g. +   * »C« for the argument »A.B.C«. +   * --------------------------------------------------------------------------- */ +  String *createLastNamespaceName(const String *nspace) const { +    if (!nspace) return NULL; +    char *c = Char(nspace); +    char *cc = c; +    if (!strstr(c, ".")) +      return NewString(nspace); + +    while (*c) { +      if (*c == '.') { +	cc = c; +      } +      ++c; +    } +    return NewString(cc + 1); +  } + +  /* --------------------------------------------------------------------------- +   * D::createOuterNamespaceNames() +   * +   * Returns a new string containing the name of the outer namespace, e.g. +   * »A.B« for the argument »A.B.C«. +   * --------------------------------------------------------------------------- */ +  String *createOuterNamespaceNames(const String *nspace) const { +    if (!nspace) return NULL; +    char *tmp = Char(nspace); +    char *c = tmp; +    char *cc = c; +    if (!strstr(c, ".")) +      return NULL; + +    while (*c) { +      if (*c == '.') { +	cc = c; +      } +      ++c; +    } +    if (cc == tmp) { +      return NULL; +    } +    return NewStringWithSize(tmp, (int)(cc - tmp)); +  } +}; + +static Language *new_swig_d() { +  return new D(); +} + +/* ----------------------------------------------------------------------------- + * swig_d()    - Instantiate module + * ----------------------------------------------------------------------------- */ +extern "C" Language *swig_d(void) { +  return new_swig_d(); +} + +/* ----------------------------------------------------------------------------- + * Usage information displayed at the command line. + * ----------------------------------------------------------------------------- */ +const char *D::usage = "\ +D Options (available with -d)\n\ +     -d2                  - Generate code for D2/Phobos (default: D1/Tango)\n\ +     -package <pkg>       - Write generated D modules into package <pkg>\n\ +     -splitproxy          - Write each D type to a dedicated file instead of\n\ +                            generating a single proxy D module.\n\ +     -wrapperlibrary <wl> - Set the name of the wrapper library to <wl>\n\ +\n"; diff --git a/contrib/tools/swig/Source/Modules/directors.cxx b/contrib/tools/swig/Source/Modules/directors.cxx new file mode 100644 index 00000000000..14e2e846619 --- /dev/null +++ b/contrib/tools/swig/Source/Modules/directors.cxx @@ -0,0 +1,270 @@ +/* ----------------------------------------------------------------------------- + * This file is part of SWIG, which is licensed as a whole under version 3  + * (or any later version) of the GNU General Public License. Some additional + * terms also apply to certain portions of SWIG. The full details of the SWIG + * license and copyrights can be found in the LICENSE and COPYRIGHT files + * included with the SWIG source code as distributed by the SWIG developers + * and at https://www.swig.org/legal.html. + * + * directors.cxx + * + * Director support functions. + * Not all of these may be necessary, and some may duplicate existing functionality + * in SWIG.  --MR + * ----------------------------------------------------------------------------- */ + +#include "swigmod.h" + +/* ----------------------------------------------------------------------------- + * Swig_csuperclass_call() + * + * Generates a fully qualified method call, including the full parameter list. + * e.g. "base::method(i, j)" + * ----------------------------------------------------------------------------- */ + +String *Swig_csuperclass_call(String *base, String *method, ParmList *l) { +  String *call = NewString(""); +  int arg_idx = 0; +  Parm *p; +  if (base) { +    Printf(call, "%s::", base); +  } +  Printf(call, "%s(", method); +  for (p = l; p; p = nextSibling(p)) { +    String *pname = Getattr(p, "name"); +    if (!pname && Cmp(Getattr(p, "type"), "void")) { +      pname = NewString(""); +      Printf(pname, "arg%d", arg_idx++); +    } +    if (p != l) +      Printf(call, ", "); +    Printv(call, pname, NIL); +  } +  Printf(call, ")"); +  return call; +} + +/* ----------------------------------------------------------------------------- + * Swig_class_declaration() + * + * Generate the start of a class/struct declaration. + * e.g. "class myclass" + * ----------------------------------------------------------------------------- */ + +String *Swig_class_declaration(Node *n, String *name) { +  if (!name) { +    name = Getattr(n, "sym:name"); +  } +  String *result = NewString(""); +  String *kind = Getattr(n, "kind"); +  Printf(result, "%s %s", kind, name); +  return result; +} + +/* ----------------------------------------------------------------------------- + * Swig_class_name() + * ----------------------------------------------------------------------------- */ + +String *Swig_class_name(Node *n) { +  String *name; +  name = Copy(Getattr(n, "sym:name")); +  return name; +} + +/* ----------------------------------------------------------------------------- + * Swig_director_declaration() + * + * Generate the full director class declaration, complete with base classes. + * e.g. "class SwigDirector_myclass : public myclass, public Swig::Director {" + * ----------------------------------------------------------------------------- */ + +String *Swig_director_declaration(Node *n) { +  String *classname = Swig_class_name(n); +  String *directorname = Language::instance()->directorClassName(n); +  String *base = Getattr(n, "classtype"); +  String *declaration = Swig_class_declaration(n, directorname); + +  Printf(declaration, " : public %s, public Swig::Director {\n", base); +  Delete(classname); +  Delete(directorname); +  return declaration; +} + + +/* ----------------------------------------------------------------------------- + * Swig_method_call() + * ----------------------------------------------------------------------------- */ + +String *Swig_method_call(const_String_or_char_ptr name, ParmList *parms) { +  String *func; +  int comma = 0; +  Parm *p = parms; +  SwigType *pt; +  String *nname; + +  func = NewString(""); +  nname = SwigType_namestr(name); +  Printf(func, "%s(", nname); +  while (p) { +    String *pname; +    pt = Getattr(p, "type"); +    if ((SwigType_type(pt) != T_VOID)) { +      if (comma) +	Printf(func, ","); +      pname = Getattr(p, "name"); +      Printf(func, "%s", pname); +      comma = 1; +    } +    p = nextSibling(p); +  } +  Printf(func, ")"); +  return func; +} + +/* ----------------------------------------------------------------------------- + * Swig_method_decl() + * + * Return a stringified version of a C/C++ declaration. + * ----------------------------------------------------------------------------- */ + +String *Swig_method_decl(SwigType *return_base_type, SwigType *decl, const_String_or_char_ptr id, List *args, int default_args) { +  String *result = NewString(""); +  bool conversion_operator = Strstr(id, "operator ") != 0 && !return_base_type; + +  Parm *parm = args; +  int arg_idx = 0; +  while (parm) { +    String *type = Getattr(parm, "type"); +    String *name = Getattr(parm, "name"); +    if (!name && Cmp(type, "void")) { +      name = NewString(""); +      Printf(name, "arg%d", arg_idx++); +      Setattr(parm, "name", name); +    } +    parm = nextSibling(parm); +  } + +  String *rettype = Copy(decl); +  String *quals = SwigType_pop_function_qualifiers(rettype); +  String *qualifiers = 0; +  if (quals) +    qualifiers = SwigType_str(quals, 0); + +  String *popped_decl = SwigType_pop_function(rettype); +  if (return_base_type) +    Append(rettype, return_base_type); + +  if (!conversion_operator) { +    SwigType *rettype_stripped = SwigType_strip_qualifiers(rettype); +    String *rtype = SwigType_str(rettype, 0); +    Append(result, rtype); +    if ((SwigType_issimple(rettype_stripped) && return_base_type) || SwigType_isqualifier(rettype)) +      Append(result, " "); +    Delete(rtype); +    Delete(rettype_stripped); +  } + +  if (id) +    Append(result, id); + +  String *args_string = default_args ? ParmList_str_defaultargs(args) : ParmList_str(args); +  Printv(result, "(", args_string, ")", NIL); + +  if (qualifiers) +    Printv(result, " ", qualifiers, NIL); + +  Delete(args_string); +  Delete(popped_decl); +  Delete(qualifiers); +  Delete(quals); +  Delete(rettype); +  return result; +} + +/* ----------------------------------------------------------------------------- + * Swig_director_emit_dynamic_cast() + * + * In order to call protected virtual director methods from the target language, we need + * to add an extra dynamic_cast to call the public C++ wrapper in the director class.  + * Also for non-static protected members when the allprotected option is on. + * ----------------------------------------------------------------------------- */ + +void Swig_director_emit_dynamic_cast(Node *n, Wrapper *f) { +  // TODO: why is the storage element removed in staticmemberfunctionHandler ?? +  if ((!is_public(n) && (is_member_director(n) || GetFlag(n, "explicitcall"))) ||  +      (is_non_virtual_protected_access(n) && !(Swig_storage_isstatic_custom(n, "staticmemberfunctionHandler:storage") ||  +                                               Swig_storage_isstatic(n)) +                                          && !Equal(nodeType(n), "constructor"))) { +    Node *parent = Getattr(n, "parentNode"); +    String *dirname; +    String *dirdecl; +    dirname = Language::instance()->directorClassName(parent); +    dirdecl = NewStringf("%s *darg = 0", dirname); +    Wrapper_add_local(f, "darg", dirdecl); +    Printf(f->code, "darg = dynamic_cast<%s *>(arg1);\n", dirname); +    Delete(dirname); +    Delete(dirdecl); +  } +} + +/* ----------------------------------------------------------------------------- + * Swig_director_parms_fixup() + * + * For each parameter in the C++ member function, copy the parameter name + * to its "lname"; this ensures that Swig_typemap_attach_parms() will do + * the right thing when it sees strings like "$1" in "directorin" typemaps. + * ----------------------------------------------------------------------------- */ + +void Swig_director_parms_fixup(ParmList *parms) { +  Parm *p; +  int i; +  for (i = 0, p = parms; p; p = nextSibling(p), ++i) { +    String *arg = Getattr(p, "name"); +    String *lname = 0; + +    if (!arg && !Equal(Getattr(p, "type"), "void")) { +      lname = NewStringf("arg%d", i); +      Setattr(p, "name", lname); +    } else +      lname = Copy(arg); + +    Setattr(p, "lname", lname); +    Delete(lname); +  } +} + +/* ----------------------------------------------------------------------------- + * Swig_director_can_unwrap() + * + * Determine whether a function's return type can be returned as an existing + * target language object instead of creating a new target language object. + * Must be a director class and only for return by pointer or reference only + * (not by value or by pointer to pointer etc). + * ----------------------------------------------------------------------------- */ + +bool Swig_director_can_unwrap(Node *n) { + +  // FIXME: this will not try to unwrap directors returned as non-director +  //        base class pointers! + +  bool unwrap = false; + +  String *type = Getattr(n, "type"); +  SwigType *t = SwigType_typedef_resolve_all(type); +  SwigType *t1 = SwigType_strip_qualifiers(t); +  SwigType *prefix = SwigType_prefix(t1); + +  if (Strcmp(prefix, "p.") == 0 || Strcmp(prefix, "r.") == 0) { +    Node *parent = Swig_methodclass(n); +    Node *module = Getattr(parent, "module"); +    Node *target = Swig_directormap(module, t1); +    if (target) +      unwrap = true; +  } + +  Delete(prefix); +  Delete(t1); +  Delete(t); + +  return unwrap; +} diff --git a/contrib/tools/swig/Source/Modules/emit.cxx b/contrib/tools/swig/Source/Modules/emit.cxx new file mode 100644 index 00000000000..74adc540096 --- /dev/null +++ b/contrib/tools/swig/Source/Modules/emit.cxx @@ -0,0 +1,556 @@ +/* ----------------------------------------------------------------------------- + * This file is part of SWIG, which is licensed as a whole under version 3  + * (or any later version) of the GNU General Public License. Some additional + * terms also apply to certain portions of SWIG. The full details of the SWIG + * license and copyrights can be found in the LICENSE and COPYRIGHT files + * included with the SWIG source code as distributed by the SWIG developers + * and at https://www.swig.org/legal.html. + * + * emit.cxx + * + * Useful functions for emitting various pieces of code. + * ----------------------------------------------------------------------------- */ + +#include "swigmod.h" +#include "cparse.h" + +/* ----------------------------------------------------------------------------- + * emit_return_variable() + * + * Emits a variable declaration for a function return value. + * The variable name is always called result. + * n => Node of the method being wrapped + * rt => the return type + * f => the wrapper to generate code into + * ----------------------------------------------------------------------------- */ + +void emit_return_variable(Node *n, SwigType *rt, Wrapper *f) { + +  if (!GetFlag(n, "tmap:out:optimal")) { +    if (rt && (SwigType_type(rt) != T_VOID)) { +      SwigType *vt = cplus_value_type(rt); +      SwigType *tt = vt ? vt : rt; +      SwigType *lt = SwigType_ltype(tt); +      String *lstr = SwigType_str(lt, Swig_cresult_name()); +      if (SwigType_ispointer(lt)) { +        Wrapper_add_localv(f, Swig_cresult_name(), lstr, "= 0", NULL); +      } else { +        Wrapper_add_local(f, Swig_cresult_name(), lstr); +      } +      if (vt) { +        Delete(vt); +      } +      Delete(lt); +      Delete(lstr); +    } +  } +} + +/* ----------------------------------------------------------------------------- + * emit_parameter_variables() + * + * Emits a list of variable declarations for function parameters. + * The variable names are always called arg1, arg2, etc... + * l => the parameter list + * f => the wrapper to generate code into + * ----------------------------------------------------------------------------- */ + +void emit_parameter_variables(ParmList *l, Wrapper *f) { + +  Parm *p; +  String *tm; + +  /* Emit function arguments */ +  Swig_cargs(f, l); + +  /* Attach typemaps to parameters */ +  /*  Swig_typemap_attach_parms("ignore",l,f); */ + +  Swig_typemap_attach_parms("default", l, f); +  Swig_typemap_attach_parms("arginit", l, f); + +  /* Apply the arginit and default */ +  p = l; +  while (p) { +    tm = Getattr(p, "tmap:arginit"); +    if (tm) { +      Printv(f->code, tm, "\n", NIL); +      p = Getattr(p, "tmap:arginit:next"); +    } else { +      p = nextSibling(p); +    } +  } + +  /* Apply the default typemap */ +  p = l; +  while (p) { +    tm = Getattr(p, "tmap:default"); +    if (tm) { +      Printv(f->code, tm, "\n", NIL); +      p = Getattr(p, "tmap:default:next"); +    } else { +      p = nextSibling(p); +    } +  } +} + +/* ----------------------------------------------------------------------------- + * emit_attach_parmmaps() + * + * Attach the standard parameter related typemaps. + * ----------------------------------------------------------------------------- */ + +void emit_attach_parmmaps(ParmList *l, Wrapper *f) { +  Swig_typemap_attach_parms("in", l, f); +  Swig_typemap_attach_parms("typecheck", l, 0); +  Swig_typemap_attach_parms("argout", l, f); +  Swig_typemap_attach_parms("check", l, f); +  Swig_typemap_attach_parms("freearg", l, f); + +  { +    /* This is compatibility code to deal with the deprecated "ignore" typemap */ +    Parm *p = l; +    Parm *np; +    while (p) { +      String *tm = Getattr(p, "tmap:in"); +      if (tm && checkAttribute(p, "tmap:in:numinputs", "0")) { +	Printv(f->code, tm, "\n", NIL); +	np = Getattr(p, "tmap:in:next"); +	while (p && (p != np)) { +	  /*	  Setattr(p,"ignore","1");    Deprecate */ +	  p = nextSibling(p); +	} +      } else if (tm) { +	p = Getattr(p, "tmap:in:next"); +      } else { +	p = nextSibling(p); +      } +    } +  } + +  /* Perform a sanity check on "in" and "freearg" typemaps.  These +     must exactly match to avoid chaos.  If a mismatch occurs, we +     nuke the freearg typemap */ +  { +    Parm *p = l; +    Parm *npin, *npfreearg; +    while (p) { +      npin = Getattr(p, "tmap:in:next"); + +      /* +         if (Getattr(p,"tmap:ignore")) { +         npin = Getattr(p,"tmap:ignore:next"); +         } else if (Getattr(p,"tmap:in")) { +         npin = Getattr(p,"tmap:in:next"); +         } +       */ + +      if (Getattr(p, "tmap:freearg")) { +	npfreearg = Getattr(p, "tmap:freearg:next"); +	if (npin != npfreearg) { +	  while (p != npin) { +	    Delattr(p, "tmap:freearg"); +	    Delattr(p, "tmap:freearg:next"); +	    p = nextSibling(p); +	  } +	} +      } +      p = npin; +    } +  } + +  /* Check for variable length arguments with no input typemap. +     If no input is defined, we set this to ignore and print a +     message. +   */ +  { +    Parm *p = l; +    Parm *lp = 0; +    while (p) { +      if (!checkAttribute(p, "tmap:in:numinputs", "0")) { +	lp = p; +	p = Getattr(p, "tmap:in:next"); +	continue; +      } +      if (SwigType_isvarargs(Getattr(p, "type"))) { +	Swig_warning(WARN_LANG_VARARGS, input_file, line_number, "Variable length arguments discarded.\n"); +	Setattr(p, "tmap:in", ""); +      } +      lp = 0; +      p = nextSibling(p); +    } + +    /* Check if last input argument is variable length argument */ +    if (lp) { +      p = lp; +      while (p) { +	if (SwigType_isvarargs(Getattr(p, "type"))) { +	  // Mark the head of the ParmList that it has varargs +	  Setattr(l, "emit:varargs", lp); +//Printf(stdout, "setting emit:varargs %s ... %s +++ %s\n", Getattr(l, "emit:varargs"), Getattr(l, "type"), Getattr(p, "type")); +	  break; +	} +	p = nextSibling(p); +      } +    } +  } + +  /*  +   * An equivalent type can be used in the typecheck typemap for SWIG to detect the overloading of equivalent +   * target language types. This is primarily for the smartptr feature, where a pointer and a smart pointer +   * are seen as equivalent types in the target language. +   */ +  { +    Parm *p = l; +    while (p) { +      String *tm = Getattr(p, "tmap:typecheck"); +      if (tm) { +	String *equivalent = Getattr(p, "tmap:typecheck:equivalent"); +	if (equivalent) { +	  String *precedence = Getattr(p, "tmap:typecheck:precedence"); +	  if (precedence && Strcmp(precedence, "0") != 0) +	    Swig_error(Getfile(tm), Getline(tm), "The 'typecheck' typemap for %s contains an 'equivalent' attribute for a 'precedence' that is not set to SWIG_TYPECHECK_POINTER or 0.\n", SwigType_str(Getattr(p, "type"), 0)); +	  SwigType *cpt = Swig_cparse_type(equivalent); +	  if (cpt) { +	    Setattr(p, "equivtype", cpt); +	    Delete(cpt); +	  } else { +	    Swig_error(Getfile(tm), Getline(tm), "Invalid type (%s) in 'equivalent' attribute in 'typecheck' typemap for type %s.\n", equivalent, SwigType_str(Getattr(p, "type"), 0)); +	  } +	} +	p = Getattr(p, "tmap:typecheck:next"); +      } else { +	p = nextSibling(p); +      } +    } +  } +} + +/* ----------------------------------------------------------------------------- + * emit_num_arguments() + * + * Calculate the total number of arguments.   This function is safe for use + * with multi-argument typemaps which may change the number of arguments in + * strange ways. + * ----------------------------------------------------------------------------- */ + +int emit_num_arguments(ParmList *parms) { +  Parm *p = parms; +  int nargs = 0; + +  while (p) { +    if (Getattr(p, "tmap:in")) { +      nargs += GetInt(p, "tmap:in:numinputs"); +      p = Getattr(p, "tmap:in:next"); +    } else { +      p = nextSibling(p); +    } +  } + +  /* DB 04/02/2003: Not sure this is necessary with tmap:in:numinputs */ +  /* +     if (parms && (p = Getattr(parms,"emit:varargs"))) { +     if (!nextSibling(p)) { +     nargs--; +     } +     } +   */ +  return nargs; +} + +/* ----------------------------------------------------------------------------- + * emit_num_required() + * + * Computes the number of required arguments.  This function is safe for + * use with multi-argument typemaps and knows how to skip over everything + * properly. Note that parameters with default values are counted unless + * the compact default args option is on. + * ----------------------------------------------------------------------------- */ + +int emit_num_required(ParmList *parms) { +  Parm *p = parms; +  int nargs = 0; +  Parm *first_default_arg = 0; +  int compactdefargs = ParmList_is_compactdefargs(p); + +  while (p) { +    if (Getattr(p, "tmap:in") && checkAttribute(p, "tmap:in:numinputs", "0")) { +      p = Getattr(p, "tmap:in:next"); +    } else { +      if (Getattr(p, "tmap:default")) +	break; +      if (Getattr(p, "value")) { +	if (!first_default_arg) +	  first_default_arg = p; +	if (compactdefargs) +	  break; +      } +      nargs += GetInt(p, "tmap:in:numinputs"); +      if (Getattr(p, "tmap:in")) { +	p = Getattr(p, "tmap:in:next"); +      } else { +	p = nextSibling(p); +      } +    } +  } + +  /* Print error message for non-default arguments following default arguments */ +  /* The error message is printed more than once with most language modules, this ought to be fixed */ +  if (first_default_arg) { +    p = first_default_arg; +    while (p) { +      if (Getattr(p, "tmap:in") && checkAttribute(p, "tmap:in:numinputs", "0")) { +	p = Getattr(p, "tmap:in:next"); +      } else { +	if (!Getattr(p, "value") && (!Getattr(p, "tmap:default"))) { +	  Swig_error(Getfile(p), Getline(p), "Non-optional argument '%s' follows an optional argument.\n", Getattr(p, "name")); +	} +	if (Getattr(p, "tmap:in")) { +	  p = Getattr(p, "tmap:in:next"); +	} else { +	  p = nextSibling(p); +	} +      } +    } +  } + +  /* DB 04/02/2003: Not sure this is necessary with tmap:in:numinputs */ +  /* +     if (parms && (p = Getattr(parms,"emit:varargs"))) { +     if (!nextSibling(p)) { +     nargs--; +     } +     } +   */ +  return nargs; +} + +/* ----------------------------------------------------------------------------- + * emit_isvarargs() + * + * Checks if a ParmList is a parameter list containing varargs. + * This function requires emit_attach_parmmaps to have been called beforehand. + * ----------------------------------------------------------------------------- */ + +int emit_isvarargs(ParmList *p) { +  if (!p) +    return 0; +  if (Getattr(p, "emit:varargs")) +    return 1; +  return 0; +} + +/* ----------------------------------------------------------------------------- + * emit_isvarargs_function() + * + * Checks for varargs in a function/constructor (can be overloaded) + * ----------------------------------------------------------------------------- */ + +bool emit_isvarargs_function(Node *n) { +  bool has_varargs = false; +  Node *over = Getattr(n, "sym:overloaded"); +  if (over) { +    for (Node *sibling = over; sibling; sibling = Getattr(sibling, "sym:nextSibling")) { +      if (ParmList_has_varargs(Getattr(sibling, "parms"))) { +	has_varargs = true; +	break; +      } +    } +  } else { +    has_varargs = ParmList_has_varargs(Getattr(n, "parms")) ? true : false; +  } +  return has_varargs; +} + +/* ----------------------------------------------------------------------------- + * void emit_mark_vararg_parms() + * + * Marks the vararg parameters which are to be ignored. + * Vararg parameters are marked as ignored if there is no 'in' varargs (...)  + * typemap. + * ----------------------------------------------------------------------------- */ + +void emit_mark_varargs(ParmList *l) { +  Parm *p = l; +  while (p) { +    if (SwigType_isvarargs(Getattr(p, "type"))) +      if (!Getattr(p, "tmap:in")) +	Setattr(p, "varargs:ignore", "1"); +    p = nextSibling(p); +  } +} + +#if 0 +/* replace_contract_args.  This function replaces argument names in contract +   specifications.   Used in conjunction with the %contract directive. */ + +static void replace_contract_args(Parm *cp, Parm *rp, String *s) { +  while (cp && rp) { +    String *n = Getattr(cp, "name"); +    if (n) { +      Replace(s, n, Getattr(rp, "lname"), DOH_REPLACE_ID); +    } +    cp = nextSibling(cp); +    rp = nextSibling(rp); +  } +} +#endif + +/* ----------------------------------------------------------------------------- + * int emit_action_code() + * + * Emits action code for a wrapper. Adds in exception handling code (%exception). + * eaction -> the action code to emit + * wrappercode -> the emitted code (output) + * ----------------------------------------------------------------------------- */ +int emit_action_code(Node *n, String *wrappercode, String *eaction) { +  assert(Getattr(n, "wrap:name")); + +  /* Look for except feature (%exception) */ +  String *tm = GetFlagAttr(n, "feature:except"); +  if (tm) +    tm = Copy(tm); +  if ((tm) && Len(tm) && (Strcmp(tm, "1") != 0)) { +    if (Strstr(tm, "$")) { +      Swig_replace_special_variables(n, parentNode(n), tm); +      Replaceall(tm, "$function", eaction); // deprecated +      Replaceall(tm, "$action", eaction); +    } +    Printv(wrappercode, tm, "\n", NIL); +    Delete(tm); +    return 1; +  } else { +    Printv(wrappercode, eaction, "\n", NIL); +    return 0; +  } +} + +/* ----------------------------------------------------------------------------- + * int emit_action() + * + * Emits the call to the wrapped function.  + * Adds in exception specification exception handling and %exception code. + * ----------------------------------------------------------------------------- */ +String *emit_action(Node *n) { +  String *actioncode = NewStringEmpty(); +  String *tm; +  String *action; +  String *wrap; +  ParmList *catchlist = Getattr(n, "catchlist"); + +  /* Look for fragments */ +  { +    String *fragment = Getattr(n, "feature:fragment"); +    if (fragment) { +      char *c, *tok; +      String *t = Copy(fragment); +      c = Char(t); +      tok = strtok(c, ","); +      while (tok) { +	String *fname = NewString(tok); +	Setfile(fname, Getfile(n)); +	Setline(fname, Getline(n)); +	Swig_fragment_emit(fname); +	Delete(fname); +	tok = strtok(NULL, ","); +      } +      Delete(t); +    } +  } + +  /* Emit wrapper code (if any) */ +  wrap = Getattr(n, "wrap:code"); +  if (wrap && Swig_filebyname("header") != Getattr(n, "wrap:code:done")) { +    File *f_code = Swig_filebyname("header"); +    if (f_code) { +      Printv(f_code, wrap, NIL); +    } +    Setattr(n, "wrap:code:done", f_code); +  } + +  action = Getattr(n, "feature:action"); +  if (!action) +    action = Getattr(n, "wrap:action"); +  assert(action != 0); + +  /* Emit contract code (if any) */ +  if (Swig_contract_mode_get()) { +    /* Preassertion */ +    tm = Getattr(n, "contract:preassert"); +    if (Len(tm)) { +      Printv(actioncode, tm, "\n", NIL); +    } +  } +  /* Exception handling code */ + +  /* saves action -> eaction for postcatching exception */ +  String *eaction = NewString(""); + +  /* If we are in C++ mode and there is an exception specification. We're going to +     enclose the block in a try block */ +  if (catchlist) { +    Printf(eaction, "try {\n"); +  } + +  String *preaction = Getattr(n, "wrap:preaction"); +  if (preaction) +    Printv(eaction, preaction, NIL); + +  Printv(eaction, action, NIL); + +  String *postaction = Getattr(n, "wrap:postaction"); +  if (postaction) +    Printv(eaction, postaction, NIL); + +  if (catchlist) { +    int unknown_catch = 0; +    int has_varargs = 0; +    Printf(eaction, "}"); +    for (Parm *ep = catchlist; ep; ep = nextSibling(ep)) { +      String *em = Swig_typemap_lookup("throws", ep, "_e", 0); +      if (em) { +        SwigType *et = Getattr(ep, "type"); +        SwigType *etr = SwigType_typedef_resolve_all(et); +        if (SwigType_isreference(etr) || SwigType_ispointer(etr) || SwigType_isarray(etr)) { +          Printf(eaction, " catch(%s) {", SwigType_str(et, "_e")); +        } else if (SwigType_isvarargs(etr)) { +          Printf(eaction, " catch(...) {"); +          has_varargs = 1; +        } else { +          Printf(eaction, " catch(%s) {", SwigType_str(et, "&_e")); +        } +        Printv(eaction, em, "\n", NIL); +        Printf(eaction, "}"); +      } else { +	Swig_warning(WARN_TYPEMAP_THROW, Getfile(n), Getline(n), "No 'throws' typemap defined for exception type '%s'\n", SwigType_str(Getattr(ep, "type"), 0)); +        unknown_catch = 1; +      } +    } +    if (unknown_catch && !has_varargs) { +      Printf(eaction, " catch(...) {\nthrow;\n}"); +    } +  } + +  /* Look for except typemap (Deprecated) */ +  tm = Swig_typemap_lookup("except", n, Swig_cresult_name(), 0); +  if (tm) { +    Setattr(n, "feature:except", tm); +    tm = 0; +  } + +  /* emit the except feature code */ +  emit_action_code(n, actioncode, eaction); + +  Delete(eaction); + +  /* Emit contract code (if any) */ +  if (Swig_contract_mode_get()) { +    /* Postassertion */ +    tm = Getattr(n, "contract:postassert"); +    if (Len(tm)) { +      Printv(actioncode, tm, "\n", NIL); +    } +  } + +  return actioncode; +} diff --git a/contrib/tools/swig/Source/Modules/go.cxx b/contrib/tools/swig/Source/Modules/go.cxx new file mode 100644 index 00000000000..bf63bec6390 --- /dev/null +++ b/contrib/tools/swig/Source/Modules/go.cxx @@ -0,0 +1,5708 @@ +/* ----------------------------------------------------------------------------- + * This file is part of SWIG, which is licensed as a whole under version 3 + * (or any later version) of the GNU General Public License. Some additional + * terms also apply to certain portions of SWIG. The full details of the SWIG + * license and copyrights can be found in the LICENSE and COPYRIGHT files + * included with the SWIG source code as distributed by the SWIG developers + * and at https://www.swig.org/legal.html. + * + * go.cxx + * + * Go language module for SWIG. + * ----------------------------------------------------------------------------- */ + +#include "swigmod.h" +#include "cparse.h" +#include <ctype.h> + +/* ---------------------------------------------------------------------- + * siphash() + * + * 64-bit SipHash-2-4 to generate unique id for each module + * ---------------------------------------------------------------------- */ + +// An unsigned 64-bit integer that works on a 32-bit host. +typedef struct { +  // Assume unsigned long is at least 32 bits. +  unsigned long hi; +  unsigned long lo; +} swig_uint64; + +// Rotate v left by bits, which must be <= 32. +static inline void _rotl(swig_uint64 *v, int bits) { +  assert(bits <= 32); +  unsigned long tmp = v->hi; +  if (bits == 32) { +    v->hi = v->lo; +    v->lo = tmp; +  } else { +    v->hi = (tmp << bits) | ((0xfffffffful & v->lo) >> (32 - bits)); +    v->lo = (v->lo << bits) | ((0xfffffffful & tmp) >> (32 - bits)); +  } +} + +// dst ^= src +static inline void _xor(swig_uint64 *dst, swig_uint64 *src) { +  dst->lo ^= src->lo; +  dst->hi ^= src->hi; +} + +// dst += src +static inline void _add(swig_uint64 *dst, swig_uint64 *src) { +  dst->lo += src->lo; +  dst->hi += src->hi + ((dst->lo & 0xfffffffful) < (src->lo&0xfffffffful) ? 1 : 0); +} +#define SIPROUND                                        \ +  do {                                                  \ +    _add(&v0, &v1); _rotl(&v1, 13); _xor(&v1, &v0); _rotl(&v0, 32); \ +    _add(&v2, &v3); _rotl(&v3, 16); _xor(&v3, &v2); \ +    _add(&v0, &v3); _rotl(&v3, 21); _xor(&v3, &v0); \ +    _add(&v2, &v1); _rotl(&v1, 17); _xor(&v1, &v2); _rotl(&v2, 32); \ +  } while(0) + +// Set out to the hash of inc/inlen. +static void siphash(swig_uint64 *out, const char *inc, unsigned long inlen) { +  /* "somepseudorandomlygeneratedbytes" */ +  swig_uint64 v0 = {0x736f6d65UL, 0x70736575UL}; +  swig_uint64 v1 = {0x646f7261UL, 0x6e646f6dUL}; +  swig_uint64 v2 = {0x6c796765UL, 0x6e657261UL}; +  swig_uint64 v3 = {0x74656462UL, 0x79746573UL}; +  swig_uint64 b; +  /* hard-coded k. */ +  swig_uint64 k0 = {0x07060504UL, 0x03020100UL}; +  swig_uint64 k1 = {0x0F0E0D0CUL, 0x0B0A0908UL}; +  int i; +  const int cROUNDS = 2, dROUNDS = 4; +  const unsigned char *in = (const unsigned char *)inc; +  const unsigned char *end = in + inlen - (inlen % 8); +  int left = inlen & 7; +  _xor(&v3, &k1); _xor(&v2, &k0); _xor(&v1, &k1); _xor(&v0, &k0); +  for (; in != end; in += 8) { +    b.hi = 0; b.lo = 0; +    for (i = 0; i < 4; i++) { +      b.lo |= ((unsigned long)in[i]) << (8*i); +    } +    for (i = 0; i < 4; i++) { +      b.hi |= ((unsigned long)in[i+4]) << (8*i); +    } +    _xor(&v3, &b); +    for (i = 0; i < cROUNDS; i++) { +      SIPROUND; +    } +    _xor(&v0, &b); +  } +  b.hi = (inlen & 0xff)<<24; b.lo = 0; +  for (; left; left--) { +    if (left > 4) { +      b.hi |= ((unsigned long)in[left-1]) << (8*left-8-32); +    } else { +      b.lo |= ((unsigned long)in[left-1]) << (8*left-8); +    } +  } +  _xor(&v3, &b); +  for(i=0; i<cROUNDS; i++) { +    SIPROUND; +  } +  _xor(&v0, &b); v2.lo ^= 0xff; +  for(i=0; i<dROUNDS; i++) { +    SIPROUND; +  } +  out->lo = 0; out->hi = 0; +  _xor(out, &v0); _xor(out, &v1); _xor(out, &v2); _xor(out, &v3); +} +#undef SIPROUND + +class GO:public Language { +  static const char *const usage; + +  // Go package name. +  String *package; +  // SWIG module name. +  String *module; +  // Flag for generating gccgo output. +  bool gccgo_flag; +  // Prefix to use with gccgo. +  String *go_prefix; +  // -fgo-prefix option. +  String *prefix_option; +  // -fgo-pkgpath option. +  String *pkgpath_option; +  // Prefix for translating %import directive to import statements. +  String *import_prefix; +  // Whether to use a shared library. +  bool use_shlib; +  // Name of shared library to import. +  String *soname; +  // Size in bits of the Go type "int".  0 if not specified. +  int intgo_type_size; + +  /* Output files */ +  File *f_c_begin; +  File *f_go_begin; + +  /* Output fragments */ +  File *f_c_runtime; +  File *f_c_header; +  File *f_c_wrappers; +  File *f_c_init; +  File *f_c_directors; +  File *f_c_directors_h; +  File *f_go_imports; +  File *f_go_runtime; +  File *f_go_header; +  File *f_go_wrappers; +  File *f_go_directors; +  File *f_cgo_comment; +  File *f_cgo_comment_typedefs; + +  // True if we imported a module. +  bool saw_import; +  // If not NULL, name of import package being processed. +  String *imported_package; +  // Build interface methods while handling a class.  This is only +  // non-NULL when we are handling methods. +  String *interfaces; +  // The class node while handling a class.  This is only non-NULL +  // when we are handling methods. +  Node *class_node; +  // The class name while handling a class.  This is only non-NULL +  // when we are handling methods.  This is the name of the class as +  // SWIG sees it. +  String *class_name; +  // The receiver name while handling a class.  This is only non-NULL +  // when we are handling methods.  This is the name of the class +  // as run through goCPointerType. +  String *class_receiver; +  // A hash table of method names that we have seen when processing a +  // class.  This lets us detect base class methods that we don't want +  // to use. +  Hash *class_methods; +  // True when we are generating the wrapper functions for a variable. +  bool making_variable_wrappers; +  // True when working with a static member function. +  bool is_static_member_function; +  // A hash table of enum types that we have seen but which may not have +  // been defined.  The index is a SwigType. +  Hash *undefined_enum_types; +  // A hash table of types that we have seen but which may not have +  // been defined.  The index is a SwigType. +  Hash *undefined_types; +  // A hash table of classes which were defined.  The index is a Go +  // type name. +  Hash *defined_types; +  // A hash table of all the go_imports already imported. The index is a full +  // import name e.g. '"runtime"' or '_ "runtime/cgo"' or 'sc "syscall"'. +  Hash *go_imports; +  // A unique ID used to make public symbols unique. +  String *unique_id; + +public: +  GO():package(NULL), +     module(NULL), +     gccgo_flag(false), +     go_prefix(NULL), +     prefix_option(NULL), +     pkgpath_option(NULL), +     import_prefix(NULL), +     use_shlib(false), +     soname(NULL), +     intgo_type_size(0), +     f_c_begin(NULL), +     f_go_begin(NULL), +     f_c_runtime(NULL), +     f_c_header(NULL), +     f_c_wrappers(NULL), +     f_c_init(NULL), +     f_c_directors(NULL), +     f_c_directors_h(NULL), +     f_go_imports(NULL), +     f_go_runtime(NULL), +     f_go_header(NULL), +     f_go_wrappers(NULL), +     f_go_directors(NULL), +     f_cgo_comment(NULL), +     f_cgo_comment_typedefs(NULL), +     saw_import(false), +     imported_package(NULL), +     interfaces(NULL), +     class_node(NULL), +     class_name(NULL), +     class_receiver(NULL), +     class_methods(NULL), +     making_variable_wrappers(false), +     is_static_member_function(false), +     undefined_enum_types(NULL), +     undefined_types(NULL), +     defined_types(NULL), +     go_imports(NULL), +     unique_id(NULL) { +    director_multiple_inheritance = 1; +    director_language = 1; +    director_prot_ctor_code = NewString("_swig_gopanic(\"accessing abstract class or protected constructor\");"); +  } + +private: +  /* ------------------------------------------------------------ +   * main() +   * ------------------------------------------------------------ */ +  virtual void main(int argc, char *argv[]) { + +    SWIG_library_directory("go"); +    bool saw_nocgo_flag = false; + +    // Process command line options. +    for (int i = 1; i < argc; i++) { +      if (argv[i]) { +	if (strcmp(argv[i], "-package") == 0) { +	  if (argv[i + 1]) { +	    package = NewString(argv[i + 1]); +	    Swig_mark_arg(i); +	    Swig_mark_arg(i + 1); +	    i++; +	  } else { +	    Swig_arg_error(); +	  } +	} else if (strcmp(argv[i], "-cgo") == 0) { +	  Swig_mark_arg(i); +	} else if (strcmp(argv[i], "-no-cgo") == 0) { +	  Swig_mark_arg(i); +	  saw_nocgo_flag = true; +	} else if (strcmp(argv[i], "-gccgo") == 0) { +	  Swig_mark_arg(i); +	  gccgo_flag = true; +	} else if (strcmp(argv[i], "-go-prefix") == 0) { +	  if (argv[i + 1]) { +	    prefix_option = NewString(argv[i + 1]); +	    Swig_mark_arg(i); +	    Swig_mark_arg(i + 1); +	    i++; +	  } else { +	    Swig_arg_error(); +	  } +	} else if (strcmp(argv[i], "-go-pkgpath") == 0) { +	  if (argv[i + 1]) { +	    pkgpath_option = NewString(argv[i + 1]); +	    Swig_mark_arg(i); +	    Swig_mark_arg(i + 1); +	    i++; +	  } else { +	    Swig_arg_error(); +	  } +	} else if (strcmp(argv[i], "-import-prefix") == 0) { +	  if (argv[i + 1]) { +	    import_prefix = NewString(argv[i + 1]); +	    Swig_mark_arg(i); +	    Swig_mark_arg(i + 1); +	    i++; +	  } else { +	    Swig_arg_error(); +	  } +	} else if (strcmp(argv[i], "-use-shlib") == 0) { +	  Swig_mark_arg(i); +	  use_shlib = true; +	} else if (strcmp(argv[i], "-soname") == 0) { +	  if (argv[i + 1]) { +	    soname = NewString(argv[i + 1]); +	    Swig_mark_arg(i); +	    Swig_mark_arg(i + 1); +	    i++; +	  } else { +	    Swig_arg_error(); +	  } +	} else if (strcmp(argv[i], "-longsize") == 0) { +	  // Ignore for backward compatibility. +	  if (argv[i + 1]) { +	    Swig_mark_arg(i); +	    Swig_mark_arg(i + 1); +	    ++i; +	  } else { +	    Swig_arg_error(); +	  } +	} else if (strcmp(argv[i], "-intgosize") == 0) { +	  if (argv[i + 1]) { +	    intgo_type_size = atoi(argv[i + 1]); +	    if (intgo_type_size != 32 && intgo_type_size != 64) { +	      Printf(stderr, "-intgosize not 32 or 64\n"); +	      Swig_arg_error(); +	    } +	    Swig_mark_arg(i); +	    Swig_mark_arg(i + 1); +	    ++i; +	  } else { +	    Swig_arg_error(); +	  } +	} else if (strcmp(argv[i], "-help") == 0) { +	  Printf(stdout, "%s\n", usage); +	} +      } +    } + +    if (saw_nocgo_flag) { +      Printf(stderr, "SWIG -go: -no-cgo option is no longer supported\n"); +      Exit(EXIT_FAILURE); +    } + +    if (gccgo_flag && !pkgpath_option && !prefix_option) { +      prefix_option = NewString("go"); +    } + +    // Add preprocessor symbol to parser. +    Preprocessor_define("SWIGGO 1", 0); + +    if (gccgo_flag) { +      Preprocessor_define("SWIGGO_GCCGO 1", 0); +    } + +    if (intgo_type_size == 32) { +      Preprocessor_define("SWIGGO_INTGO_SIZE 32", 0); +    } else if (intgo_type_size == 64) { +      Preprocessor_define("SWIGGO_INTGO_SIZE 64", 0); +    } else { +      Preprocessor_define("SWIGGO_INTGO_SIZE 0", 0); +    } + +    // Add typemap definitions. +    SWIG_typemap_lang("go"); +    SWIG_config_file("go.swg"); + +    allow_overloading(); +  } + +  /* --------------------------------------------------------------------- +   * top() +   * +   * For gc, we are going to create the following files: +   * +   * 1) A .c or .cxx file compiled with gcc.  This file will contain +   *    function wrappers.  Each wrapper will take a pointer to a +   *    struct holding the arguments, unpack them, and call the real +   *    function. +   * +   * 2) A .go file which defines the Go form of all types, and which +   *    defines Go function wrappers.  Each wrapper will call the C +   *    function wrapper in the second file. +   * +   * 3) A .c file compiled with 6c/8c.  This file will define +   *    Go-callable C function wrappers.  Each wrapper will use +   *    cgocall to call the function wrappers in the first file. +   * +   * When generating code for gccgo, we don't need the third file, and +   * the function wrappers in the first file have a different form. +   * +   * --------------------------------------------------------------------- */ + +  virtual int top(Node *n) { +    Node *optionsnode = Getattr(Getattr(n, "module"), "options"); +    if (optionsnode) { +      if (Getattr(optionsnode, "directors")) { +	allow_directors(); +      } +      if (Getattr(optionsnode, "dirprot")) { +	allow_dirprot(); +      } +      allow_allprotected(GetFlag(optionsnode, "allprotected")); +    } + +    module = Getattr(n, "name"); +    if (!package) { +      package = Copy(module); +    } +    if (!soname && use_shlib) { +      soname = Copy(package); +      Append(soname, ".so"); +    } + +    if (gccgo_flag) { +      String *pref; +      if (pkgpath_option) { +	pref = pkgpath_option; +      } else { +	pref = prefix_option; +      } +      go_prefix = NewString(""); +      for (char *p = Char(pref); *p != '\0'; p++) { +	if ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || (*p >= '0' && *p <= '9') || *p == '.' || *p == '$') { +	  Putc(*p, go_prefix); +	} else { +	  Putc('_', go_prefix); +	} +      } +      if (!pkgpath_option) { +	Append(go_prefix, "."); +	Append(go_prefix, getModuleName(package)); +      } +    } + +    // Get filenames. + +    String *swig_filename = Getattr(n, "infile"); +    String *c_filename = Getattr(n, "outfile"); +    String *c_filename_h = Getattr(n, "outfile_h"); + +    String *go_filename = NewString(""); +    Printf(go_filename, "%s%s.go", SWIG_output_directory(), module); + +    // Generate a unique ID based on a hash of the SWIG input. +    swig_uint64 hash = {0, 0}; +    FILE *swig_input = Swig_open(swig_filename); +    if (swig_input == NULL) { +      FileErrorDisplay(swig_filename); +      Exit(EXIT_FAILURE); +    } +    String *swig_input_content = Swig_read_file(swig_input); +    siphash(&hash, Char(swig_input_content), Len(swig_input_content)); +    Delete(swig_input_content); +    fclose(swig_input); +    unique_id = NewString(""); +    Printf(unique_id, "_%s_%08x%08x", getModuleName(package), hash.hi, hash.lo); + +    // Open files. + +    f_c_begin = NewFile(c_filename, "w", SWIG_output_files()); +    if (!f_c_begin) { +      FileErrorDisplay(c_filename); +      Exit(EXIT_FAILURE); +    } + +    if (directorsEnabled()) { +      if (!c_filename_h) { +	Printf(stderr, "Unable to determine outfile_h\n"); +	Exit(EXIT_FAILURE); +      } +      f_c_directors_h = NewFile(c_filename_h, "w", SWIG_output_files()); +      if (!f_c_directors_h) { +	FileErrorDisplay(c_filename_h); +	Exit(EXIT_FAILURE); +      } +    } + +    f_go_begin = NewFile(go_filename, "w", SWIG_output_files()); +    if (!f_go_begin) { +      FileErrorDisplay(go_filename); +      Exit(EXIT_FAILURE); +    } + +    f_c_runtime = NewString(""); +    f_c_header = NewString(""); +    f_c_wrappers = NewString(""); +    f_c_init = NewString(""); +    f_c_directors = NewString(""); +    f_go_imports = NewString(""); +    f_go_runtime = NewString(""); +    f_go_header = NewString(""); +    f_go_wrappers = NewString(""); +    f_go_directors = NewString(""); +    f_cgo_comment = NewString(""); +    f_cgo_comment_typedefs = NewString(""); + +    Swig_register_filebyname("begin", f_c_begin); +    Swig_register_filebyname("runtime", f_c_runtime); +    Swig_register_filebyname("header", f_c_header); +    Swig_register_filebyname("wrapper", f_c_wrappers); +    Swig_register_filebyname("init", f_c_init); +    Swig_register_filebyname("director", f_c_directors); +    Swig_register_filebyname("director_h", f_c_directors_h); +    Swig_register_filebyname("go_begin", f_go_begin); +    Swig_register_filebyname("go_imports", f_go_imports); +    Swig_register_filebyname("go_runtime", f_go_runtime); +    Swig_register_filebyname("go_header", f_go_header); +    Swig_register_filebyname("go_wrapper", f_go_wrappers); +    Swig_register_filebyname("go_director", f_go_directors); +    Swig_register_filebyname("cgo_comment", f_cgo_comment); +    Swig_register_filebyname("cgo_comment_typedefs", f_cgo_comment_typedefs); + +    Swig_banner(f_c_begin); + +    Swig_obligatory_macros(f_c_runtime, "GO"); + +    if (CPlusPlus) { +      Printf(f_c_begin, "\n// source: %s\n\n", swig_filename); +    } else { +      Printf(f_c_begin, "\n/* source: %s */\n\n", swig_filename); +    } + +    Printf(f_c_runtime, "#define SWIGMODULE %s\n", module); + +    if (gccgo_flag) { +      Printf(f_c_runtime, "#define SWIGGO_PREFIX %s\n", go_prefix); +    } + +    if (directorsEnabled()) { +      Printf(f_c_runtime, "#define SWIG_DIRECTORS\n"); + +      Swig_banner(f_c_directors_h); +      Printf(f_c_directors_h, "\n// source: %s\n\n", swig_filename); + +      Printf(f_c_directors_h, "#ifndef SWIG_%s_WRAP_H_\n", module); +      Printf(f_c_directors_h, "#define SWIG_%s_WRAP_H_\n\n", module); +      Printf(f_c_directors_h, "class Swig_memory;\n\n"); + +      Printf(f_c_directors, "\n// C++ director class methods.\n"); +      String *filename = Swig_file_filename(c_filename_h); +      Printf(f_c_directors, "#include \"%s\"\n\n", filename); +      Delete(filename); +    } + +    Swig_banner(f_go_begin); +    Printf(f_go_begin, "\n// source: %s\n", swig_filename); + +    Printv(f_cgo_comment_typedefs, "/*\n", NULL); + +    // The cgo program defines the intgo type after our function +    // definitions, but we want those definitions to be able to use +    // intgo also. +    Printv(f_cgo_comment_typedefs, "#define intgo swig_intgo\n", NULL); +    Printv(f_cgo_comment_typedefs, "typedef void *swig_voidp;\n", NULL); + +    // Output module initialization code. + +    Printf(f_go_begin, "\npackage %s\n\n", getModuleName(package)); + +    // All the C++ wrappers should be extern "C". + +    Printv(f_c_wrappers, "#ifdef __cplusplus\n", "extern \"C\" {\n", "#endif\n\n", NULL); + +    // Set up the hash table for types not defined by SWIG. + +    undefined_enum_types = NewHash(); +    undefined_types = NewHash(); +    defined_types = NewHash(); +    go_imports = NewHash(); + +    // Emit code. + +    Language::top(n); + +    if (directorsEnabled()) { +      // Insert director runtime into the f_runtime file (make it occur before %header section) +      Swig_insert_file("director_common.swg", f_c_runtime); +      Swig_insert_file("director.swg", f_c_runtime); +    } + +    Delete(go_imports); + +    // Write out definitions for the types not defined by SWIG. + +    if (Len(undefined_enum_types) > 0) +      Printv(f_go_wrappers, "\n", NULL); +    for (Iterator p = First(undefined_enum_types); p.key; p = Next(p)) { +      String *name = p.item; +      Printv(f_go_wrappers, "type ", name, " int\n", NULL); +    } + +    Printv(f_go_wrappers, "\n", NULL); +    for (Iterator p = First(undefined_types); p.key; p = Next(p)) { +      String *ty = goType(NULL, p.key); +      if (!Getattr(defined_types, ty)) { +	String *cp = goCPointerType(p.key, false); +	if (!Getattr(defined_types, cp)) { +	  Printv(f_go_wrappers, "type ", cp, " uintptr\n", NULL); +	  Printv(f_go_wrappers, "type ", ty, " interface {\n", NULL); +	  Printv(f_go_wrappers, "\tSwigcptr() uintptr;\n", NULL); +	  Printv(f_go_wrappers, "}\n", NULL); +	  Printv(f_go_wrappers, "func (p ", cp, ") Swigcptr() uintptr {\n", NULL); +	  Printv(f_go_wrappers, "\treturn uintptr(p)\n", NULL); +	  Printv(f_go_wrappers, "}\n\n", NULL); +	} +	Delete(cp); +      } +      Delete(ty); +    } +    Delete(undefined_enum_types); +    Delete(undefined_types); +    Delete(defined_types); + +    /* Write and cleanup */ + +    Dump(f_c_header, f_c_runtime); + +    if (directorsEnabled()) { +      Printf(f_c_directors_h, "#endif\n"); +      Delete(f_c_directors_h); +      f_c_directors_h = NULL; + +      Dump(f_c_directors, f_c_runtime); +      Delete(f_c_directors); +      f_c_directors = NULL; +    } + +    // End the extern "C". +    Printv(f_c_wrappers, "#ifdef __cplusplus\n", "}\n", "#endif\n\n", NULL); + +    // End the cgo comment. +    Printv(f_cgo_comment, "#undef intgo\n", NULL); +    Printv(f_cgo_comment, "*/\n", NULL); +    Printv(f_cgo_comment, "import \"C\"\n", NULL); +    Printv(f_cgo_comment, "\n", NULL); + +    bool need_panic = false; +    if (Strstr(f_c_runtime, "SWIG_contract_assert(") != 0 || Strstr(f_c_wrappers, "SWIG_contract_assert(") != 0) { +      Printv(f_c_begin, "\n#define SWIG_contract_assert(expr, msg) if (!(expr)) { _swig_gopanic(msg); } else\n\n", NULL); +      need_panic = true; +    } + +    if (!gccgo_flag && (need_panic || Strstr(f_c_runtime, "_swig_gopanic") != 0 || Strstr(f_c_wrappers, "_swig_gopanic") != 0)) { +      Printv(f_go_header, "//export cgo_panic_", unique_id, "\n", NULL); +      Printv(f_go_header, "func cgo_panic_", unique_id, "(p *byte) {\n", NULL); +      Printv(f_go_header, "\ts := (*[1024]byte)(unsafe.Pointer(p))[:]\n", NULL); +      Printv(f_go_header, "\tfor i, b := range s {\n", NULL); +      Printv(f_go_header, "\t\tif b == 0 {\n", NULL); +      Printv(f_go_header, "\t\t\tpanic(string(s[:i]))\n", NULL); +      Printv(f_go_header, "\t\t}\n", NULL); +      Printv(f_go_header, "\t}\n", NULL); +      Printv(f_go_header, "\tpanic(string(s))\n", NULL); +      Printv(f_go_header, "}\n\n", NULL); + +      Printv(f_c_begin, "\nextern\n", NULL); +      Printv(f_c_begin, "#ifdef __cplusplus\n", NULL); +      Printv(f_c_begin, "  \"C\"\n", NULL); +      Printv(f_c_begin, "#endif\n", NULL); +      Printv(f_c_begin, "  void cgo_panic_", unique_id, "(const char*);\n", NULL); +      Printv(f_c_begin, "static void _swig_gopanic(const char *p) {\n", NULL); +      Printv(f_c_begin, "  cgo_panic_", unique_id, "(p);\n", NULL); +      Printv(f_c_begin, "}\n\n", NULL); +    } + +    Dump(f_c_runtime, f_c_begin); +    Dump(f_c_wrappers, f_c_begin); +    Dump(f_c_init, f_c_begin); +    Dump(f_cgo_comment_typedefs, f_go_begin); +    Dump(f_cgo_comment, f_go_begin); +    Dump(f_go_imports, f_go_begin); +    Dump(f_go_header, f_go_begin); +    Dump(f_go_runtime, f_go_begin); +    Dump(f_go_wrappers, f_go_begin); +    if (directorsEnabled()) { +      Dump(f_go_directors, f_go_begin); +    } +    Delete(f_c_runtime); +    Delete(f_c_header); +    Delete(f_c_wrappers); +    Delete(f_c_init); +    Delete(f_go_imports); +    Delete(f_go_runtime); +    Delete(f_go_header); +    Delete(f_go_wrappers); +    Delete(f_go_directors); +    Delete(f_cgo_comment); +    Delete(f_cgo_comment_typedefs); +    Delete(f_c_begin); +    Delete(f_go_begin); + +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * importDirective() +   * +   * Handle a SWIG import statement by generating a Go import +   * statement. +   * ------------------------------------------------------------ */ + +  virtual int importDirective(Node *n) { +    String *hold_import = imported_package; +    String *modname = Getattr(n, "module"); +    if (modname) { +      if (!Getattr(go_imports, modname)) { +        Setattr(go_imports, modname, modname); +        Printv(f_go_imports, "import \"", NULL); +	if (import_prefix) { +	  Printv(f_go_imports, import_prefix, "/", NULL); +	} +	Printv(f_go_imports, modname, "\"\n", NULL); +      } +      imported_package = modname; +      saw_import = true; +    } +    int r = Language::importDirective(n); +    imported_package = hold_import; +    return r; +  } + +  /* ---------------------------------------------------------------------- +   * Language::insertDirective() +   * +   * If the section is go_imports, store them for later. +   * ---------------------------------------------------------------------- */ +  virtual int insertDirective(Node *n) { +    char *section = Char(Getattr(n, "section")); +    if ((ImportMode && !Getattr(n, "generated")) || +        !section || (strcmp(section, "go_imports") != 0)) { +      return Language::insertDirective(n); +    } + +    char *code = Char(Getattr(n, "code")); +    char *pch = strtok(code, ","); +    while (pch != NULL) { +      // Do not import same thing more than once. +      if (!Getattr(go_imports, pch)) { +        Setattr(go_imports, pch, pch); +        Printv(f_go_imports, "import ", pch, "\n", NULL); +      } +      pch = strtok(NULL, ","); +    } +    return SWIG_OK; +  } + +  /* ---------------------------------------------------------------------- +   * functionWrapper() +   * +   * Implement a function. +   * ---------------------------------------------------------------------- */ + +  virtual int functionWrapper(Node *n) { +    if (GetFlag(n, "feature:ignore")) { +      return SWIG_OK; +    } + +    // We don't need explicit calls. +    if (GetFlag(n, "explicitcall")) { +      return SWIG_OK; +    } + +    // Don't emit constructors for abstract director classes.  They +    // will never succeed anyhow. +    if (Swig_methodclass(n) && Swig_directorclass(n) +	&& Strcmp(Char(Getattr(n, "wrap:action")), director_prot_ctor_code) == 0) { +      return SWIG_OK; +    } + +    String *name = Getattr(n, "sym:name"); +    String *nodetype = Getattr(n, "nodeType"); +    bool is_static = is_static_member_function || isStatic(n); +    bool is_friend = isFriend(n); +    bool is_ctor_dtor = false; + +    SwigType *result = Getattr(n, "type"); + +    // For some reason SWIG changs the "type" value during the call to +    // functionWrapper.  We need to remember the type for possible +    // overload processing. +    Setattr(n, "go:type", Copy(result)); + +    String *go_name; + +    String *r1 = NULL; +    if (making_variable_wrappers) { +      // Change the name of the variable setter and getter functions +      // to be more Go like. + +      bool is_set = Strcmp(Char(name) + Len(name) - 4, "_set") == 0; +      assert(is_set || Strcmp(Char(name) + Len(name) - 4, "_get") == 0); + +      // Start with Set or Get. +      go_name = NewString(is_set ? "Set" : "Get"); + +      // If this is a static variable, put in the class name, +      // capitalized. +      if (is_static && class_name) { +	String *ccn = exportedName(class_name); +	Append(go_name, ccn); +	Delete(ccn); +      } + +      // Add the rest of the name, capitalized, dropping the _set or +      // _get. +      String *c1 = removeClassname(name); +      String *c2 = exportedName(c1); +      char *p = Char(c2); +      int len = Len(p); +      for (int i = 0; i < len - 4; ++i) { +	Putc(p[i], go_name); +      } +      Delete(c2); +      Delete(c1); + +      if (!checkIgnoredParameters(n, go_name)) { +	Delete(go_name); +	return SWIG_NOWRAP; +      } +    } else if (Cmp(nodetype, "constructor") == 0) { +      is_ctor_dtor = true; + +      // Change the name of a constructor to be more Go like.  Change +      // new_ to New, and capitalize the class name. +      assert(Strncmp(name, "new_", 4) == 0); +      String *c1 = NewString(Char(name) + 4); +      String *c2 = exportedName(c1); +      go_name = NewString("New"); +      Append(go_name, c2); +      Delete(c2); +      Delete(c1); + +      if (Swig_methodclass(n) && Swig_directorclass(n)) { +	// The core SWIG code skips the first parameter when +	// generating the $nondirector_new string.  Recreate the +	// action in this case.  But don't it if we are using the +	// special code for an abstract class. +	String *call = Swig_cppconstructor_call(getClassType(), +						Getattr(n, "parms")); +	SwigType *type = Copy(getClassType()); +	SwigType_add_pointer(type); +	String *cres = Swig_cresult(type, Swig_cresult_name(), call); +	Setattr(n, "wrap:action", cres); +      } +    } else if (Cmp(nodetype, "destructor") == 0) { +      // No need to emit protected destructors. +      if (!is_public(n)) { +	return SWIG_OK; +      } + +      is_ctor_dtor = true; + +      // Change the name of a destructor to be more Go like.  Change +      // delete_ to Delete and capitalize the class name. +      assert(Strncmp(name, "delete_", 7) == 0); +      String *c1 = NewString(Char(name) + 7); +      String *c2 = exportedName(c1); +      go_name = NewString("Delete"); +      Append(go_name, c2); +      Delete(c2); +      Delete(c1); + +      result = NewString("void"); +      r1 = result; +    } else { +      if (!checkFunctionVisibility(n, NULL)) { +	return SWIG_OK; +      } + +      go_name = buildGoName(name, is_static, is_friend); + +      if (!checkIgnoredParameters(n, go_name)) { +	Delete(go_name); +	return SWIG_NOWRAP; +      } +    } + +    String *overname = NULL; +    if (Getattr(n, "sym:overloaded")) { +      overname = Getattr(n, "sym:overname"); +    } else { +      String *scope; +      if (!class_name || is_static || is_ctor_dtor) { +	scope = NULL; +      } else { +	scope = NewString("swiggoscope."); +	Append(scope, class_name); +      } +      if (!checkNameConflict(go_name, n, scope)) { +	Delete(go_name); +	return SWIG_NOWRAP; +      } +    } + +    String *wname = Swig_name_wrapper(name); +    if (overname) { +      Append(wname, overname); +    } +    Append(wname, unique_id); +    Setattr(n, "wrap:name", wname); + +    ParmList *parms = Getattr(n, "parms"); +    Setattr(n, "wrap:parms", parms); + +    int r = makeWrappers(n, go_name, overname, wname, NULL, parms, result, is_static); +    if (r != SWIG_OK) { +      return r; +    } + +    if (Getattr(n, "sym:overloaded") && !Getattr(n, "sym:nextSibling")) { +      String *scope ; +      if (!class_name || is_static || is_ctor_dtor) { +	scope = NULL; +      } else { +	scope = NewString("swiggoscope."); +	Append(scope, class_name); +      } +      if (!checkNameConflict(go_name, n, scope)) { +	Delete(go_name); +	return SWIG_NOWRAP; +      } + +      String *receiver = class_receiver; +      if (is_static || is_ctor_dtor) { +	receiver = NULL; +      } +      r = makeDispatchFunction(n, go_name, receiver, is_static, NULL, false); +      if (r != SWIG_OK) { +	return r; +      } +    } + +    Delete(wname); +    Delete(go_name); +    Delete(r1); + +    return SWIG_OK; +  } + +  /* ---------------------------------------------------------------------- +   * staticmemberfunctionHandler() +   * +   * For some reason the language code removes the "storage" attribute +   * for a static function before calling functionWrapper, which means +   * that we have no way of knowing whether a function is static or +   * not.  That makes no sense in the Go context.  Here we note that a +   * function is static. +   * ---------------------------------------------------------------------- */ + +  int staticmemberfunctionHandler(Node *n) { +    assert(!is_static_member_function); +    is_static_member_function = true; +    int r = Language::staticmemberfunctionHandler(n); +    is_static_member_function = false; +    return r; +  } + +  /* ---------------------------------------------------------------------- +   * makeWrappers() +   * +   * Write out the various function wrappers. +   * n: The function we are emitting. +   * go_name: The name of the function in Go. +   * overname: The overload string for overloaded function. +   * wname: The SWIG wrapped name--the name of the C function. +   * base: A list of the names of base classes, in the case where this +   *       is a virtual method not defined in the current class. +   * parms: The parameters. +   * result: The result type. +   * is_static: Whether this is a static method or member. +   * ---------------------------------------------------------------------- */ + +  int makeWrappers(Node *n, String *go_name, String *overname, String *wname, List *base, ParmList *parms, SwigType *result, bool is_static) { + +    assert(result); + +    int ret = SWIG_OK; + +    int r = makeCgoWrappers(n, go_name, overname, wname, base, parms, result, is_static); +    if (r != SWIG_OK) { +      ret = r; +    } + +    if (class_methods) { +      Setattr(class_methods, Getattr(n, "name"), NewString("")); +    } + +    return ret; +  } + +  /* ---------------------------------------------------------------------- +   * struct cgoWrapperInfo +   * +   * Information needed by the CGO wrapper functions. +   * ---------------------------------------------------------------------- */ + +  struct cgoWrapperInfo { +    // The function we are generating code for. +    Node *n; +    // The name of the Go function. +    String *go_name; +    // The overload string for an overloaded function. +    String *overname; +    // The name of the C wrapper function. +    String *wname; +    // The base classes. +    List *base; +    // The parameters. +    ParmList *parms; +    // The result type. +    SwigType *result; +    // Whether this is a static function, not a class method. +    bool is_static; +    // The Go receiver type. +    String *receiver; +    // Whether this is a class constructor. +    bool is_constructor; +    // Whether this is a class destructor. +    bool is_destructor; +  }; + +  /* ---------------------------------------------------------------------- +   * makeCgoWrappers() +   * +   * Write out the wrappers for a function when producing cgo input +   * files. +   * ---------------------------------------------------------------------- */ + +  int makeCgoWrappers(Node *n, String *go_name, String *overname, String *wname, List *base, ParmList *parms, SwigType *result, bool is_static) { +    Swig_save("makeCgoWrappers", n, "emit:cgotype", "emit:cgotypestruct", NULL); + +    cgoWrapperInfo info; + +    info.n = n; +    info.go_name = go_name; +    info.overname = overname; +    info.wname = wname; +    info.base = base; +    info.parms = parms; +    info.result = result; +    info.is_static = is_static; + +    info.receiver = class_receiver; +    if (is_static) { +      info.receiver = NULL; +    } + +    String *nodetype = Getattr(n, "nodeType"); +    info.is_constructor = Cmp(nodetype, "constructor") == 0; +    info.is_destructor = Cmp(nodetype, "destructor") == 0; +    if (info.is_constructor || info.is_destructor) { +      assert(class_receiver); +      assert(!base); +      info.receiver = NULL; +    } + +    int ret = SWIG_OK; + +    int r = cgoGoWrapper(&info); +    if (r != SWIG_OK) { +      ret = r; +    } + +    r = cgoCommentWrapper(&info); +    if (r != SWIG_OK) { +      ret = r; +    } + +    r = cgoGccWrapper(&info); +    if (r != SWIG_OK) { +      ret = r; +    } + +    Swig_restore(n); + +    return ret; +  } + +  /* ---------------------------------------------------------------------- +   * cgoGoWrapper() +   * +   * Write out Go code to call a cgo function.  This code will go into +   * the generated Go output file. +   * ---------------------------------------------------------------------- */ +  int cgoGoWrapper(const cgoWrapperInfo *info) { + +    Wrapper *dummy = initGoTypemaps(info->parms); + +    bool add_to_interface = interfaces && !info->is_constructor && !info->is_destructor && !info->is_static && !info->overname && checkFunctionVisibility(info->n, NULL); + +    Printv(f_go_wrappers, "func ", NULL); + +    Parm *p = info->parms; +    int pi = 0; + +    // Add the receiver first if this is a method. +    if (info->receiver) { +      Printv(f_go_wrappers, "(", NULL); +      if (info->base && info->receiver) { +	Printv(f_go_wrappers, "_swig_base", NULL); +      } else { +	Printv(f_go_wrappers, Getattr(p, "lname"), NULL); +	p = nextParm(p); +	++pi; +      } +      Printv(f_go_wrappers, " ", info->receiver, ") ", NULL); +    } + +    Printv(f_go_wrappers, info->go_name, NULL); +    if (info->overname) { +      Printv(f_go_wrappers, info->overname, NULL); +    } +    Printv(f_go_wrappers, "(", NULL); + +    // If we are doing methods, add this method to the interface. +    if (add_to_interface) { +      Printv(interfaces, "\t", info->go_name, "(", NULL); +    } + +    // Write out the parameters to both the function definition and +    // the interface. + +    String *parm_print = NewString(""); + +    int parm_count = emit_num_arguments(info->parms); +    int required_count = emit_num_required(info->parms); +    int args = 0; + +    for (; pi < parm_count; ++pi) { +      p = getParm(p); +      if (pi == 0 && info->is_destructor) { +	String *cl = exportedName(class_name); +	Printv(parm_print, Getattr(p, "lname"), " ", cl, NULL); +	Delete(cl); +	++args; +      } else { +	if (args > 0) { +	  Printv(parm_print, ", ", NULL); +	} +	++args; +	if (pi >= required_count) { +	  Printv(parm_print, "_swig_args ...interface{}", NULL); +	  break; +	} +	Printv(parm_print, Getattr(p, "lname"), " ", NULL); +	String *tm = goType(p, Getattr(p, "type")); +	Printv(parm_print, tm, NULL); +	Delete(tm); +      } +      p = nextParm(p); +    } + +    Printv(parm_print, ")", NULL); + +    // Write out the result type. +    if (info->is_constructor) { +      String *cl = exportedName(class_name); +      Printv(parm_print, " (_swig_ret ", cl, ")", NULL); +      Delete(cl); +    } else { +      if (SwigType_type(info->result) != T_VOID) { +	String *tm = goType(info->n, info->result); +	Printv(parm_print, " (_swig_ret ", tm, ")", NULL); +	Delete(tm); +      } +    } + +    Printv(f_go_wrappers, parm_print, NULL); +    if (add_to_interface) { +      Printv(interfaces, parm_print, "\n", NULL); +    } + +    // Write out the function body. + +    Printv(f_go_wrappers, " {\n", NULL); + +    if (parm_count > required_count) { +      Parm *p = info->parms; +      int i; +      for (i = 0; i < required_count; ++i) { +	p = getParm(p); +	p = nextParm(p); +      } +      for (; i < parm_count; ++i) { +	p = getParm(p); +	String *tm = goType(p, Getattr(p, "type")); +	Printv(f_go_wrappers, "\tvar ", Getattr(p, "lname"), " ", tm, "\n", NULL); +	Printf(f_go_wrappers, "\tif len(_swig_args) > %d {\n", i - required_count); +	Printf(f_go_wrappers, "\t\t%s = _swig_args[%d].(%s)\n", Getattr(p, "lname"), i - required_count, tm); +	Printv(f_go_wrappers, "\t}\n", NULL); +	Delete(tm); +	p = nextParm(p); +      } +    } + +    String *call = NewString("\t"); + +    String *ret_type = NULL; +    bool memcpy_ret = false; +    String *wt = NULL; +    if (SwigType_type(info->result) != T_VOID) { +      if (info->is_constructor) { +	ret_type = exportedName(class_name); +      } else { +	ret_type = goImType(info->n, info->result); +      } +      Printv(f_go_wrappers, "\tvar swig_r ", ret_type, "\n", NULL); + +      bool c_struct_type; +      Delete(cgoTypeForGoValue(info->n, info->result, &c_struct_type)); +      if (c_struct_type) { +	memcpy_ret = true; +      } + +      if (memcpy_ret) { +	Printv(call, "swig_r_p := ", NULL); +      } else { +	Printv(call, "swig_r = (", ret_type, ")(", NULL); +      } + +      if (info->is_constructor || goTypeIsInterface(info->n, info->result)) { +	if (info->is_constructor) { +	  wt = Copy(class_receiver); +	} else { +	  wt = goWrapperType(info->n, info->result, true); +	} +	Printv(call, wt, "(", NULL); +      } +    } + +    Printv(call, "C.", info->wname, "(", NULL); + +    args = 0; + +    if (parm_count > required_count) { +      Printv(call, "C.swig_intgo(len(_swig_args))", NULL); +      ++args; +    } + +    if (info->base && info->receiver) { +      if (args > 0) { +	Printv(call, ", ", NULL); +      } +      ++args; +      Printv(call, "C.uintptr_t(_swig_base)", NULL); +    } + +    p = info->parms; +    for (int i = 0; i < parm_count; ++i) { +      p = getParm(p); +      if (args > 0) { +	Printv(call, ", ", NULL); +      } +      ++args; + +      SwigType *pt = Getattr(p, "type"); +      String *ln = Getattr(p, "lname"); + +      String *ivar = NewStringf("_swig_i_%d", i); + +      String *goin = goGetattr(p, "tmap:goin"); +      if (goin == NULL) { +	Printv(f_go_wrappers, "\t", ivar, " := ", NULL); +	bool need_close = false; +	if ((i == 0 && info->is_destructor) || ((i > 0 || !info->receiver || info->base || info->is_constructor) && goTypeIsInterface(p, pt))) { +	  Printv(f_go_wrappers, "getSwigcptr(", NULL); +	  need_close = true; +	} +	Printv(f_go_wrappers, ln, NULL); +	if (need_close) { +	  Printv(f_go_wrappers, ")", NULL); +	} +	Printv(f_go_wrappers, "\n", NULL); +	Setattr(p, "emit:goinput", ln); +      } else { +	String *itm = goImType(p, pt); +	Printv(f_go_wrappers, "\tvar ", ivar, " ", itm, "\n", NULL); +	goin = Copy(goin); +	Replaceall(goin, "$input", ln); +	Replaceall(goin, "$result", ivar); +	Printv(f_go_wrappers, goin, "\n", NULL); +	Delete(goin); +	Setattr(p, "emit:goinput", ivar); +      } + +      bool c_struct_type; +      String *ct = cgoTypeForGoValue(p, pt, &c_struct_type); +      if (c_struct_type) { +	Printv(call, "*(*C.", ct, ")(unsafe.Pointer(&", ivar, "))", NULL); +      } else { +	Printv(call, "C.", ct, "(", ivar, ")", NULL); +      } +      Delete(ct); + +      p = nextParm(p); +    } + +    Printv(f_go_wrappers, call, ")", NULL); +    Delete(call); + +    if (wt) { +      // Close the type conversion to the wrapper type. +      Printv(f_go_wrappers, ")", NULL); +    } +    if (SwigType_type(info->result) != T_VOID && !memcpy_ret) { +      // Close the type conversion of the return value. +      Printv(f_go_wrappers, ")", NULL); +    } + +    Printv(f_go_wrappers, "\n", NULL); + +    if (memcpy_ret) { +      Printv(f_go_wrappers, "\tswig_r = *(*", ret_type, ")(unsafe.Pointer(&swig_r_p))\n", NULL); +    } +    if (ret_type) { +      Delete(ret_type); +    } + +    goargout(info->parms); + +    if (SwigType_type(info->result) != T_VOID) { + +      Swig_save("cgoGoWrapper", info->n, "type", "tmap:goout", NULL); +      Setattr(info->n, "type", info->result); + +      String *goout = goTypemapLookup("goout", info->n, "swig_r"); +      if (goout == NULL) { +	Printv(f_go_wrappers, "\treturn swig_r\n", NULL); +      } else { +	String *tm = goType(info->n, info->result); +	Printv(f_go_wrappers, "\tvar swig_r_1 ", tm, "\n", NULL); +	goout = Copy(goout); +	Replaceall(goout, "$input", "swig_r"); +	Replaceall(goout, "$result", "swig_r_1"); +	Printv(f_go_wrappers, goout, "\n", NULL); +	Printv(f_go_wrappers, "\treturn swig_r_1\n", NULL); +      } + +      Swig_restore(info->n); +    } + +    Printv(f_go_wrappers, "}\n\n", NULL); + +    DelWrapper(dummy); + +    return SWIG_OK; +  } + +  /* ---------------------------------------------------------------------- +   * cgoCommentWrapper() +   * +   * Write out a cgo function to call a C/C++ function.  This code +   * will go into the cgo comment in the generated Go output file. +   * ---------------------------------------------------------------------- */ +  int cgoCommentWrapper(const cgoWrapperInfo *info) { +    String *ret_type; +    if (SwigType_type(info->result) == T_VOID) { +      ret_type = NewString("void"); +    } else { +      bool c_struct_type; +      ret_type = cgoTypeForGoValue(info->n, info->result, &c_struct_type); +    } + +    Printv(f_cgo_comment, "extern ", ret_type, " ", info->wname, "(", NULL); + +    Delete(ret_type); + +    int parm_count = emit_num_arguments(info->parms); +    int required_count = emit_num_required(info->parms); +    int args = 0; + +    if (parm_count > required_count) { +      Printv(f_cgo_comment, "intgo _swig_args", NULL); +      ++args; +    } + +    if (info->base && info->receiver) { +      if (args > 0) { +	Printv(f_cgo_comment, ", ", NULL); +      } +      ++args; +      Printv(f_cgo_comment, "uintptr_t _swig_base", NULL); +    } + +    Parm *p = info->parms; +    for (int i = 0; i < parm_count; ++i) { +      p = getParm(p); +      if (args > 0) { +	Printv(f_cgo_comment, ", ", NULL); +      } +      ++args; + +      SwigType *pt = Getattr(p, "type"); +      String *ln = Getattr(p, "lname"); + +      bool c_struct_type; +      String *ct = cgoTypeForGoValue(p, pt, &c_struct_type); +      Printv(f_cgo_comment, ct, " ", ln, NULL); +      Delete(ct); + +      p = nextParm(p); +    } + +    if (args == 0) { +      Printv(f_cgo_comment, "void", NULL); +    } + +    Printv(f_cgo_comment, ");\n", NULL); + +    return SWIG_OK; +  } + +  /* ---------------------------------------------------------------------- +   * cgoGccWrapper() +   * +   * Write out code to the C/C++ wrapper file.  This code will be +   * called by the code generated by cgoCommentWrapper. +   * ---------------------------------------------------------------------- */ +  int cgoGccWrapper(const cgoWrapperInfo *info) { +    Wrapper *f = NewWrapper(); + +    Swig_save("cgoGccWrapper", info->n, "parms", NULL); + +    ParmList *parms = info->parms; + +    Parm *base_parm = NULL; +    if (info->base && !isStatic(info->n)) { +      SwigType *base_type = Copy(getClassType()); +      SwigType_add_pointer(base_type); +      base_parm = NewParm(base_type, NewString("arg1"), info->n); +      set_nextSibling(base_parm, parms); +      parms = base_parm; +    } + +    emit_parameter_variables(parms, f); +    emit_attach_parmmaps(parms, f); +    int parm_count = emit_num_arguments(parms); +    int required_count = emit_num_required(parms); + +    emit_return_variable(info->n, info->result, f); + +    // Start the function definition. + +    String *fnname = NewString(""); +    Printv(fnname, info->wname, "(", NULL); + +    int args = 0; + +    if (parm_count > required_count) { +      Printv(fnname, "intgo _swig_optargc", NULL); +      ++args; +    } + +    Parm *p = parms; +    for (int i = 0; i < parm_count; ++i) { +      if (args > 0) { +	Printv(fnname, ", ", NULL); +      } +      ++args; + +      p = getParm(p); + +      SwigType *pt = Copy(Getattr(p, "type")); +      if (SwigType_isarray(pt) && Getattr(p, "tmap:gotype") == NULL) { +	SwigType_del_array(pt); +	SwigType_add_pointer(pt); +      } +      String *pn = NewStringf("_swig_go_%d", i); +      String *ct = gcCTypeForGoValue(p, pt, pn); +      Printv(fnname, ct, NULL); +      Delete(ct); +      Delete(pn); +      Delete(pt); + +      p = nextParm(p); +    } +       +    Printv(fnname, ")", NULL); + +    if (SwigType_type(info->result) == T_VOID) { +      Printv(f->def, "void ", fnname, NULL); +    } else { +      String *ct = gcCTypeForGoValue(info->n, info->result, fnname); +      Printv(f->def, ct, NULL); +      Delete(ct); + +      String *ln = NewString("_swig_go_result"); +      ct = gcCTypeForGoValue(info->n, info->result, ln); +      Wrapper_add_local(f, "_swig_go_result", ct); +      Delete(ct); +      Delete(ln); +    } + +    Delete(fnname); + +    Printv(f->def, " {\n", NULL); + +    // Apply the in typemaps. + +    p = parms; +    for (int i = 0; i < parm_count; ++i) { +      p = getParm(p); +      String *tm = Getattr(p, "tmap:in"); +      if (!tm) { +	Swig_warning(WARN_TYPEMAP_IN_UNDEF, input_file, line_number, "unable to use type %s as a function argument\n", SwigType_str(Getattr(p, "type"), 0)); +      } else { +	tm = Copy(tm); +	String *pn = NewStringf("_swig_go_%d", i); +	Replaceall(tm, "$input", pn); +	if (i < required_count) { +	  Printv(f->code, "\t", tm, "\n", NULL); +	} else { +	  Printf(f->code, "\tif (_swig_optargc > %d) {\n", i - required_count); +	  Printv(f->code, "\t\t", tm, "\n", NULL); +	  Printv(f->code, "\t}\n", NULL); +	} +	Delete(tm); +	Setattr(p, "emit:input", pn); +      } +      p = nextParm(p); +    } + +    Printv(f->code, "\n", NULL); + +    // Do the real work of the function. + +    checkConstraints(parms, f); + +    emitGoAction(info->n, info->base, parms, info->result, f); + +    argout(parms, f); + +    cleanupFunction(info->n, f, parms); + +    if (SwigType_type(info->result) != T_VOID) { +      Printv(f->code, "\treturn _swig_go_result;\n", NULL); +    } + +    Printv(f->code, "}\n", NULL); + +    Wrapper_print(f, f_c_wrappers); + +    Swig_restore(info->n); + +    DelWrapper(f); +    if (base_parm) { +      Delete(base_parm); +    } + +    return SWIG_OK; +  } + +  /* ---------------------------------------------------------------------- +   * initGoTypemaps() +   * +   * Initialize the typenames for a Go wrapper, returning a dummy +   * Wrapper*.  Also set consistent names for the parameters. +   * ---------------------------------------------------------------------- */ + +  Wrapper* initGoTypemaps(ParmList *parms) { +    Wrapper *dummy = NewWrapper(); +    emit_attach_parmmaps(parms, dummy); + +    Parm *p = parms; +    int parm_count = emit_num_arguments(parms); +    for (int i = 0; i < parm_count; ++i) { +      p = getParm(p); +      Swig_cparm_name(p, i); +      p = nextParm(p); +    } + +    Swig_typemap_attach_parms("default", parms, dummy); +    Swig_typemap_attach_parms("gotype", parms, dummy); +    Swig_typemap_attach_parms("goin", parms, dummy); +    Swig_typemap_attach_parms("goargout", parms, dummy); +    Swig_typemap_attach_parms("imtype", parms, dummy); + +    return dummy; +  } + +  /* ----------------------------------------------------------------------- +   * checkConstraints() +   * +   * Check parameter constraints if any.  This is used for the C/C++ +   * function.  This assumes that each parameter has an "emit:input" +   * property with the name to use to refer to that parameter. +   * ----------------------------------------------------------------------- */ + +  void checkConstraints(ParmList *parms, Wrapper *f) { +    Parm *p = parms; +    while (p) { +      String *tm = Getattr(p, "tmap:check"); +      if (!tm) { +	p = nextSibling(p); +      } else { +	tm = Copy(tm); +	Replaceall(tm, "$input", Getattr(p, "emit:input")); +	Printv(f->code, tm, "\n\n", NULL); +	Delete(tm); +	p = Getattr(p, "tmap:check:next"); +      } +    } +  } + +  /* ----------------------------------------------------------------------- +   * emitGoAction() +   * +   * Emit the action of the function.  This is used for the C/C++ function. +   * ----------------------------------------------------------------------- */ + +  void emitGoAction(Node *n, List *base, ParmList *parms, SwigType *result, Wrapper *f) { +    String *actioncode; +    if (!base || isStatic(n)) { +      Swig_director_emit_dynamic_cast(n, f); +      actioncode = emit_action(n); +    } else { +      // Call the base class method. +      actioncode = NewString(""); + +      String *current = NewString(""); +      Printv(current, Getattr(parms, "lname"), NULL); + +      int vc = 0; +      for (Iterator bi = First(base); bi.item; bi = Next(bi)) { +	Printf(actioncode, "  %s *swig_b%d = (%s *)%s;\n", bi.item, vc, bi.item, current); +	Delete(current); +	current = NewString(""); +	Printf(current, "swig_b%d", vc); +	++vc; +      } + +      String *code = Copy(Getattr(n, "wrap:action")); +      Replace(code, Getattr(parms, "lname"), current, DOH_REPLACE_ANY | DOH_REPLACE_ID); +      Delete(current); +      Printv(actioncode, code, "\n", NULL); +    } + +    Swig_save("emitGoAction", n, "type", "tmap:out", NULL); + +    Setattr(n, "type", result); + +    String *tm = Swig_typemap_lookup_out("out", n, Swig_cresult_name(), f, actioncode); +    if (!tm) { +      Swig_warning(WARN_TYPEMAP_OUT_UNDEF, input_file, line_number, "Unable to use return type %s\n", SwigType_str(result, 0)); +    } else { +      Replaceall(tm, "$result", "_swig_go_result"); +      if (GetFlag(n, "feature:new")) { +	Replaceall(tm, "$owner", "1"); +      } else { +	Replaceall(tm, "$owner", "0"); +      } +      Printv(f->code, tm, "\n", NULL); +      Delete(tm); +    } + +    Swig_restore(n); +  } + +  /* ----------------------------------------------------------------------- +   * argout() +   * +   * Handle argument output code if any.  This is used for the C/C++ +   * function.  This assumes that each parameter has an "emit:input" +   * property with the name to use to refer to that parameter. +   * ----------------------------------------------------------------------- */ + +  void argout(ParmList *parms, Wrapper *f) { +    Parm *p = parms; +    while (p) { +      String *tm = Getattr(p, "tmap:argout"); +      if (!tm) { +	p = nextSibling(p); +      } else { +	tm = Copy(tm); +	Replaceall(tm, "$result", Swig_cresult_name()); +	Replaceall(tm, "$input", Getattr(p, "emit:input")); +	Printv(f->code, tm, "\n", NULL); +	Delete(tm); +	p = Getattr(p, "tmap:argout:next"); +      } +    } +  } + +  /* ----------------------------------------------------------------------- +   * goargout() +   * +   * Handle Go argument output code if any.  This is used for the Go +   * function.  This assumes that each parameter has an "emit:goinput" +   * property with the name to use to refer to that parameter. +   * ----------------------------------------------------------------------- */ + +  void goargout(ParmList *parms) { +    Parm *p = parms; +    while (p) { +      String *tm = Getattr(p, "tmap:goargout"); +      if (!tm) { +	p = nextSibling(p); +      } else { +	tm = Copy(tm); +	Replaceall(tm, "$result", "swig_r"); +	Replaceall(tm, "$input", Getattr(p, "emit:goinput")); +	Printv(f_go_wrappers, tm, "\n", NULL); +	Delete(tm); +	p = Getattr(p, "tmap:goargout:next"); +      } +    } + +    // If we need to memcpy a parameter to pass it to the C code, the +    // compiler may think that the parameter is not live during the +    // function call.  If the garbage collector runs while the C/C++ +    // function is running, the parameter may be freed.  Force the +    // compiler to see the parameter as live across the C/C++ function. +    int parm_count = emit_num_arguments(parms); +    p = parms; +    for (int i = 0; i < parm_count; ++i) { +      p = getParm(p); +      bool c_struct_type; +      Delete(cgoTypeForGoValue(p, Getattr(p, "type"), &c_struct_type)); +      if (c_struct_type) { +	Printv(f_go_wrappers, "\tif Swig_escape_always_false {\n", NULL); +	Printv(f_go_wrappers, "\t\tSwig_escape_val = ", Getattr(p, "emit:goinput"), "\n", NULL); +	Printv(f_go_wrappers, "\t}\n", NULL); +      } +      p = nextParm(p); +    } +  } + +  /* ----------------------------------------------------------------------- +   * freearg() +   * +   * Handle argument cleanup code if any.  This is used for the C/C++ +   * function.  This assumes that each parameter has an "emit:input" +   * property with the name to use to refer to that parameter. +   * ----------------------------------------------------------------------- */ + +  String *freearg(ParmList *parms) { +    String *ret = NewString(""); +    Parm *p = parms; +    while (p) { +      String *tm = Getattr(p, "tmap:freearg"); +      if (!tm) { +	p = nextSibling(p); +      } else { +	tm = Copy(tm); +	Replaceall(tm, "$input", Getattr(p, "emit:input")); +	Printv(ret, tm, "\n", NULL); +	Delete(tm); +	p = Getattr(p, "tmap:freearg:next"); +      } +    } +    return ret; +  } + +  /* ----------------------------------------------------------------------- +   * cleanupFunction() +   * +   * Final function cleanup code. +   * ----------------------------------------------------------------------- */ + +  void cleanupFunction(Node *n, Wrapper *f, ParmList *parms) { +    String *cleanup = freearg(parms); +    Printv(f->code, cleanup, NULL); + +    if (GetFlag(n, "feature:new")) { +      String *tm = Swig_typemap_lookup("newfree", n, Swig_cresult_name(), 0); +      if (tm) { +	Printv(f->code, tm, "\n", NULL); +	Delete(tm); +      } +    } + +    Replaceall(f->code, "$cleanup", cleanup); +    Delete(cleanup); + +    /* See if there is any return cleanup code */ +    String *tm; +    if ((tm = Swig_typemap_lookup("ret", n, Swig_cresult_name(), 0))) { +      Printf(f->code, "%s\n", tm); +      Delete(tm); +    } + +    Replaceall(f->code, "$symname", Getattr(n, "sym:name")); +  } + +  /* ----------------------------------------------------------------------- +   * variableHandler() +   * +   * This exists just to set the making_variable_wrappers flag. +   * ----------------------------------------------------------------------- */ + +  virtual int variableHandler(Node *n) { +    assert(!making_variable_wrappers); +    making_variable_wrappers = true; +    int r = Language::variableHandler(n); +    making_variable_wrappers = false; +    return r; +  } + +  /* ----------------------------------------------------------------------- +   * constantWrapper() +   * +   * Product a const declaration. +   * ------------------------------------------------------------------------ */ + +  virtual int constantWrapper(Node *n) { +    SwigType *type = Getattr(n, "type"); + +    if (!SwigType_issimple(type) && SwigType_type(type) != T_STRING) { +      return goComplexConstant(n, type); +    } + +    if (Swig_storage_isstatic(n)) { +      return goComplexConstant(n, type); +    } + +    String *go_name = buildGoName(Getattr(n, "sym:name"), false, false); + +    String *tm = goType(n, type); +    String *value = Getattr(n, "value"); + +    String *copy = NULL; +    if (SwigType_type(type) == T_BOOL) { +      if (Cmp(value, "true") != 0 && Cmp(value, "false") != 0) { +	return goComplexConstant(n, type); +      } +    } else if (SwigType_type(type) == T_STRING || SwigType_type(type) == T_CHAR) { +      // Backslash sequences are somewhat different in Go and C/C++. +      if (Strchr(value, '\\') != 0) { +	return goComplexConstant(n, type); +      } +    } else { +      // Accept a 0x prefix, and strip combinations of u and l +      // suffixes.  Otherwise accept digits, decimal point, and +      // exponentiation.  Treat anything else as too complicated to +      // handle as a Go constant. +      char *p = Char(value); +      int len = (int)strlen(p); +      bool need_copy = false; +      while (len > 0) { +	char c = p[len - 1]; +	if (c != 'l' && c != 'L' && c != 'u' && c != 'U') { +	  break; +	} +	--len; +	need_copy = true; +      } +      bool is_hex = false; +      int i = 0; +      if (p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) { +	i = 2; +	is_hex = true; +      } +      for (; i < len; ++i) { +	switch (p[i]) { +	case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': +	  break; +	case 'a': case 'b': case 'c': case 'd': case 'f': case 'A': case 'B': case 'C': case 'D': case 'F': +	  if (!is_hex) { +	    return goComplexConstant(n, type); +	  } +	  break; +	case '.': case 'e': case 'E': case '+': case '-': +	  break; +	default: +	  return goComplexConstant(n, type); +	} +      } +      if (need_copy) { +	copy = Copy(value); +	Replaceall(copy, p + len, ""); +	value = copy; +      } +    } + +    if (!checkNameConflict(go_name, n, NULL)) { +      Delete(tm); +      Delete(go_name); +      Delete(copy); +      return SWIG_NOWRAP; +    } + +    Printv(f_go_wrappers, "const ", go_name, " ", tm, " = ", NULL); +    if (SwigType_type(type) == T_STRING) { +      Printv(f_go_wrappers, "\"", value, "\"", NULL); +    } else if (SwigType_type(type) == T_CHAR) { +      Printv(f_go_wrappers, "'", value, "'", NULL); +    } else { +      Printv(f_go_wrappers, value, NULL); +    } + +    Printv(f_go_wrappers, "\n", NULL); + +    Delete(tm); +    Delete(go_name); +    Delete(copy); + +    return SWIG_OK; +  } + +  /* ---------------------------------------------------------------------- +   * enumDeclaration() +   * +   * A C++ enum type turns into a Named go int type. +   * ---------------------------------------------------------------------- */ + +  virtual int enumDeclaration(Node *n) { +    if (getCurrentClass() && (cplus_mode != PUBLIC)) +      return SWIG_NOWRAP; + +    String *name = goEnumName(n); +    if (Strcmp(name, "int") != 0) { +      if (!ImportMode || !imported_package) { +	if (!checkNameConflict(name, n, NULL)) { +	  Delete(name); +	  return SWIG_NOWRAP; +	} +	Printv(f_go_wrappers, "type ", name, " int\n", NULL); +      } else { +	String *nw = NewString(""); +	Printv(nw, getModuleName(imported_package), ".", name, NULL); +	Setattr(n, "go:enumname", nw); +      } +    } +    Delete(name); + +    return Language::enumDeclaration(n); +  } + +  /* ----------------------------------------------------------------------- +   * enumvalueDeclaration() +   * +   * Declare a single value of an enum type.  We fetch the value by +   * calling a C/C++ function. +   * ------------------------------------------------------------------------ */ + +  virtual int enumvalueDeclaration(Node *n) { +    if (!is_public(n)) { +      return SWIG_OK; +    } + +    Swig_require("enumvalueDeclaration", n, "*sym:name", NIL); +    Node *parent = parentNode(n); + +    if (Getattr(parent, "unnamed")) { +      Setattr(n, "type", NewString("int")); +    } else { +      Setattr(n, "type", Getattr(parent, "enumtype")); +    } + +    if (GetFlag(parent, "scopedenum")) { +      String *symname = Getattr(n, "sym:name"); +      symname = Swig_name_member(0, Getattr(parent, "sym:name"), symname); +      Setattr(n, "sym:name", symname); +      Delete(symname); +    } + +    int ret = goComplexConstant(n, Getattr(n, "type")); +    Swig_restore(n); +    return ret; +  } + +  /* ----------------------------------------------------------------------- +   * goComplexConstant() +   * +   * Handle a const declaration for something which is not a Go constant. +   * ------------------------------------------------------------------------ */ + +  int goComplexConstant(Node *n, SwigType *type) { +    String *symname = Getattr(n, "sym:name"); +    if (!symname) { +      symname = Getattr(n, "name"); +    } + +    String *varname = buildGoName(symname, true, false); + +    if (!checkNameConflict(varname, n, NULL)) { +      Delete(varname); +      return SWIG_NOWRAP; +    } + +    String *rawval = Getattr(n, "rawval"); +    if (rawval && Len(rawval)) { +      // Based on Swig_VargetToFunction +      String *nname = NewStringf("(%s)", rawval); +      String *call; +      if (SwigType_isclass(type)) { +	call = NewStringf("%s", nname); +      } else { +	call = SwigType_lcaststr(type, nname); +      } +      String *cres = Swig_cresult(type, Swig_cresult_name(), call); +      Setattr(n, "wrap:action", cres); +      Delete(nname); +      Delete(call); +      Delete(cres); +    } else { +      String *get = NewString(""); +      Printv(get, Swig_cresult_name(), " = ", NULL); + +      char quote; +      if (Getattr(n, "wrappedasconstant")) { +        quote = '\0'; +      } else if (SwigType_type(type) == T_CHAR) { +        quote = '\''; +      } else if (SwigType_type(type) == T_STRING) { +        Printv(get, "(char *)", NULL); +        quote = '"'; +      } else { +        quote = '\0'; +      } + +      if (quote != '\0') { +        Printf(get, "%c", quote); +      } + +      Printv(get, Getattr(n, "value"), NULL); + +      if (quote != '\0') { +        Printf(get, "%c", quote); +      } + +      Printv(get, ";\n", NULL); + +      Setattr(n, "wrap:action", get); +      Delete(get); +    } + +    String *sname = Copy(symname); +    if (class_name) { +      Append(sname, "_"); +      Append(sname, class_name); +    } + +    String *go_name = NewString("_swig_get"); +    if (class_name) { +      Append(go_name, class_name); +      Append(go_name, "_"); +    } +    Append(go_name, sname); + +    String *wname = Swig_name_wrapper(sname); +    Append(wname, unique_id); +    Setattr(n, "wrap:name", wname); + +    int r = makeWrappers(n, go_name, NULL, wname, NULL, NULL, type, true); + +    if (r != SWIG_OK) { +      return r; +    } + +    String *t = goType(n, type); +    Printv(f_go_wrappers, "var ", varname, " ", t, " = ", go_name, "()\n", NULL); + +    Delete(varname); +    Delete(t); +    Delete(go_name); +    Delete(sname); + +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * classHandler() +   * +   * For a C++ class, in Go we generate both a struct and an +   * interface.  The interface will declare all the class public +   * methods.  We will define all the methods on the struct, so that +   * the struct meets the interface.  We then expect users of the +   * class to use the interface. +   * ------------------------------------------------------------ */ + +  virtual int classHandler(Node *n) { +    class_node = n; + +    List *baselist = Getattr(n, "bases"); +    bool has_base_classes = baselist && Len(baselist) > 0; + +    String *name = Getattr(n, "sym:name"); + +    String *go_name = exportedName(name); + +    if (!checkNameConflict(go_name, n, NULL)) { +      Delete(go_name); +      SetFlag(n, "go:conflict"); +      return SWIG_NOWRAP; +    } + +    String *go_type_name = goCPointerType(Getattr(n, "classtypeobj"), true); + +    class_name = name; +    class_receiver = go_type_name; +    class_methods = NewHash(); + +    int isdir = GetFlag(n, "feature:director"); +    int isnodir = GetFlag(n, "feature:nodirector"); +    bool is_director = isdir && !isnodir; + +    Printv(f_go_wrappers, "type ", go_type_name, " uintptr\n\n", NULL); + +    // A method to return the pointer to the C++ class.  This is used +    // by generated code to convert between the interface and the C++ +    // value. +    Printv(f_go_wrappers, "func (p ", go_type_name, ") Swigcptr() uintptr {\n", NULL); +    Printv(f_go_wrappers, "\treturn (uintptr)(p)\n", NULL); +    Printv(f_go_wrappers, "}\n\n", NULL); + +    // A method used as a marker for the class, to avoid invalid +    // interface conversions when using multiple inheritance. +    Printv(f_go_wrappers, "func (p ", go_type_name, ") SwigIs", go_name, "() {\n", NULL); +    Printv(f_go_wrappers, "}\n\n", NULL); + +    if (is_director) { +      // Return the interface passed to the NewDirector function. +      Printv(f_go_wrappers, "func (p ", go_type_name, ") DirectorInterface() interface{} {\n", NULL); +      Printv(f_go_wrappers, "\treturn nil\n", NULL); +      Printv(f_go_wrappers, "}\n\n", NULL); +    } + +    // We have seen a definition for this type. +    Setattr(defined_types, go_name, go_name); +    Setattr(defined_types, go_type_name, go_type_name); + +    interfaces = NewString(""); + +    int r = Language::classHandler(n); +    if (r != SWIG_OK) { +      return r; +    } + +    if (has_base_classes) { +      // For each method defined in a base class but not defined in +      // this class, we need to define the method in this class.  We +      // can't use anonymous field inheritance because it works +      // differently in Go and in C++. + +      Hash *local = NewHash(); +      for (Node *ni = Getattr(n, "firstChild"); ni; ni = nextSibling(ni)) { + +	if (!is_public(ni)) { +	  continue; +	} + +	String *type = Getattr(ni, "nodeType"); +	if (Cmp(type, "constructor") == 0 || Cmp(type, "destructor") == 0) { +	  continue; +	} + +	String *cname = Getattr(ni, "sym:name"); +	if (!cname) { +	  cname = Getattr(ni, "name"); +	} +	if (cname) { +	  Setattr(local, cname, NewString("")); +	} +      } + +      for (Iterator b = First(baselist); b.item; b = Next(b)) { +	List *bases = NewList(); +	Append(bases, Getattr(b.item, "classtype")); +	int r = addBase(n, b.item, bases, local); +	if (r != SWIG_OK) { +	  return r; +	} +	Delete(bases); +      } + +      Delete(local); + +      Hash *parents = NewHash(); +      addFirstBaseInterface(n, parents, baselist); +      int r = addExtraBaseInterfaces(n, parents, baselist); +      Delete(parents); +      if (r != SWIG_OK) { +	return r; +      } +    } + +    Printv(f_go_wrappers, "type ", go_name, " interface {\n", NULL); +    Printv(f_go_wrappers, "\tSwigcptr() uintptr\n", NULL); +    Printv(f_go_wrappers, "\tSwigIs", go_name, "()\n", NULL); + +    if (is_director) { +      Printv(f_go_wrappers, "\tDirectorInterface() interface{}\n", NULL); +    } + +    Append(f_go_wrappers, interfaces); +    Printv(f_go_wrappers, "}\n\n", NULL); +    Delete(interfaces); + +    interfaces = NULL; +    class_name = NULL; +    class_receiver = NULL; +    class_node = NULL; +    Delete(class_methods); +    class_methods = NULL; + +    Delete(go_type_name); + +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * addBase() +   * +   * Implement methods and members defined in a parent class for a +   * child class. +   * ------------------------------------------------------------ */ + +  int addBase(Node *n, Node *base, List *bases, Hash *local) { +    if (GetFlag(base, "feature:ignore")) { +      return SWIG_OK; +    } + +    for (Node *ni = Getattr(base, "firstChild"); ni; ni = nextSibling(ni)) { +      int r = goBaseEntry(n, bases, local, ni); +      if (r != SWIG_OK) { +	return r; +      } +    } + +    List *baselist = Getattr(base, "bases"); +    if (baselist && Len(baselist) > 0) { +      for (Iterator b = First(baselist); b.item; b = Next(b)) { +	List *nb = Copy(bases); +	Append(nb, Getattr(b.item, "classtype")); +	int r = addBase(n, b.item, nb, local); +	Delete(nb); +	if (r != SWIG_OK) { +	  return r; +	} +      } +    } + +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * goBaseEntry() +   * +   * Implement one entry defined in a parent class for a child class. +   * n is the child class. +   * ------------------------------------------------------------ */ + +  int goBaseEntry(Node* n, List* bases, Hash *local, Node* entry) { +    if (GetFlag(entry, "feature:ignore")) { +      return SWIG_OK; +    } + +    if (!is_public(entry)) { +      return SWIG_OK; +    } + +    String *type = Getattr(entry, "nodeType"); +    if (Strcmp(type, "constructor") == 0 || Strcmp(type, "destructor") == 0 || Strcmp(type, "enum") == 0 || Strcmp(type, "using") == 0 || Strcmp(type, "classforward") == 0 || Strcmp(type, "template") == 0) { +      return SWIG_OK; +    } + +    if (Strcmp(type, "extend") == 0) { +      for (Node* extend = firstChild(entry); extend; extend = nextSibling(extend)) { +	if (isStatic(extend)) { +	  // If we don't do this, the extend_default test case fails. +	  continue; +	} + +	int r = goBaseEntry(n, bases, local, extend); +	if (r != SWIG_OK) { +	  return r; +	} +      } +      return SWIG_OK; +    } + +    String *storage = Getattr(entry, "storage"); +    if (storage && (Strcmp(storage, "typedef") == 0 || Strcmp(storage, "friend") == 0)) { +      return SWIG_OK; +    } + +    String *mname = Getattr(entry, "sym:name"); +    if (!mname) { +      return SWIG_OK; +    } + +    String *lname = Getattr(entry, "name"); +    if (Getattr(class_methods, lname)) { +      return SWIG_OK; +    } +    if (Getattr(local, lname)) { +      return SWIG_OK; +    } +    Setattr(local, lname, NewString("")); + +    String *ty = NewString(Getattr(entry, "type")); +    SwigType_push(ty, Getattr(entry, "decl")); +    String *fullty = SwigType_typedef_resolve_all(ty); +    bool is_function = SwigType_isfunction(fullty) ? true : false; +    Delete(ty); +    Delete(fullty); + +    if (is_function) { +      int r = goBaseMethod(n, bases, entry); +      if (r != SWIG_OK) { +	return r; +      } + +      if (Getattr(entry, "sym:overloaded")) { +	for (Node *on = Getattr(entry, "sym:nextSibling"); on; on = Getattr(on, "sym:nextSibling")) { +	  r = goBaseMethod(n, bases, on); +	  if (r != SWIG_OK) { +	    return r; +	  } +	} + +	String *receiver = class_receiver; +	bool is_static = isStatic(entry); +	if (is_static) { +	  receiver = NULL; +	} +	String *go_name = buildGoName(Getattr(entry, "sym:name"), is_static, false); +	r = makeDispatchFunction(entry, go_name, receiver, is_static, NULL, false); +	Delete(go_name); +	if (r != SWIG_OK) { +	    return r; +	} +      } +    } else { +      int r = goBaseVariable(n, bases, entry); +      if (r != SWIG_OK) { +	return r; +      } +    } + +    return SWIG_OK; +  } + + +  /* ------------------------------------------------------------ +   * goBaseMethod() +   * +   * Implement a method defined in a parent class for a child class. +   * ------------------------------------------------------------ */ + +  int goBaseMethod(Node *method_class, List *bases, Node *method) { +    String *symname = Getattr(method, "sym:name"); +    if (!validIdentifier(symname)) { +      return SWIG_OK; +    } + +    String *name = NewString(""); +    Printv(name, Getattr(method_class, "sym:name"), "_", symname, NULL); + +    bool is_static = isStatic(method); + +    String *go_name = buildGoName(name, is_static, false); + +    String *overname = NULL; +    if (Getattr(method, "sym:overloaded")) { +      overname = Getattr(method, "sym:overname"); +    } +    String *wname = Swig_name_wrapper(name); +    if (overname) { +      Append(wname, overname); +    } +    Append(wname, unique_id); + +    String *result = NewString(Getattr(method, "type")); +    SwigType_push(result, Getattr(method, "decl")); +    if (SwigType_isqualifier(result)) { +      Delete(SwigType_pop(result)); +    } +    Delete(SwigType_pop_function(result)); + +    // If the base method is imported, wrap:action may not be set. +    Swig_save("goBaseMethod", method, "wrap:name", "wrap:action", "parms", NULL); +    Setattr(method, "wrap:name", wname); +    if (!Getattr(method, "wrap:action")) { +      if (!is_static) { +	Swig_MethodToFunction(method, getNSpace(), getClassType(), (Getattr(method, "template") ? SmartPointer : Extend | SmartPointer), NULL, false); +	// Remove any self parameter that was just added. +	ParmList *parms = Getattr(method, "parms"); +	if (parms && Getattr(parms, "self")) { +	  parms = CopyParmList(nextSibling(parms)); +	  Setattr(method, "parms", parms); +	} +      } else { +	String *call = Swig_cfunction_call(Getattr(method, "name"), Getattr(method, "parms")); +	Setattr(method, "wrap:action", Swig_cresult(Getattr(method, "type"), Swig_cresult_name(), call)); +      } +    } + +    // A method added by %extend in a base class may have void parms. +    ParmList* parms = Getattr(method, "parms"); +    if (parms != NULL && SwigType_type(Getattr(parms, "type")) == T_VOID) { +      parms = NULL; +    } + +    int r = makeWrappers(method, go_name, overname, wname, bases, parms, result, is_static); + +    Swig_restore(method); + +    Delete(result); +    Delete(go_name); +    Delete(name); + +    return r; +  } + +  /* ------------------------------------------------------------ +   * goBaseVariable() +   * +   * Add accessors for a member variable defined in a parent class for +   * a child class. +   * ------------------------------------------------------------ */ + +  int goBaseVariable(Node *var_class, List *bases, Node *var) { +    if (isStatic(var)) { +      return SWIG_OK; +    } + +    String *var_name = buildGoName(Getattr(var, "sym:name"), false, false); + +    Swig_save("goBaseVariable", var, "type", "wrap:action", NULL); + +    // For a pointer type we apparently have to wrap in the decl. +    SwigType *var_type = NewString(Getattr(var, "type")); +    SwigType_push(var_type, Getattr(var, "decl")); +    Setattr(var, "type", var_type); + +    SwigType *vt = Copy(var_type); + +    int flags = Extend | SmartPointer | use_naturalvar_mode(var); +    if (isNonVirtualProtectedAccess(var)) { +      flags |= CWRAP_ALL_PROTECTED_ACCESS; +    } + +    // Copied from Swig_wrapped_member_var_type. +    if (SwigType_isclass(vt)) { +      if (flags & CWRAP_NATURAL_VAR) { +	if (CPlusPlus) { +	  if (!SwigType_isconst(vt)) { +	    SwigType_add_qualifier(vt, "const"); +	  } +	  SwigType_add_reference(vt); +	} +      } else { +	SwigType_add_pointer(vt); +      } +    } + +    String *mname = Swig_name_member(getNSpace(), Getattr(var_class, "sym:name"), var_name); + +    if (is_assignable(var)) { +      for (Iterator ki = First(var); ki.key; ki = Next(ki)) { +	if (Strncmp(ki.key, "tmap:", 5) == 0) { +	  Delattr(var, ki.key); +	} +      } +      Swig_save("goBaseVariableSet", var, "name", "sym:name", "type", NULL); + +      String *mname_set = NewString("Set"); +      Append(mname_set, mname); + +      String *go_name = NewString("Set"); +      Append(go_name, var_name); + +      Swig_MembersetToFunction(var, class_name, flags); + +      String *wname = Swig_name_wrapper(mname_set); +      Append(wname, unique_id); +      ParmList *parms = NewParm(vt, var_name, var); +      String *result = NewString("void"); +      int r = makeWrappers(var, go_name, NULL, wname, bases, parms, result, false); +      if (r != SWIG_OK) { +	return r; +      } +      Delete(wname); +      Delete(parms); +      Delete(result); +      Delete(go_name); +      Delete(mname_set); + +      Swig_restore(var); +      for (Iterator ki = First(var); ki.key; ki = Next(ki)) { +	if (Strncmp(ki.key, "tmap:", 5) == 0) { +	  Delattr(var, ki.key); +	} +      } +    } + +    Swig_MembergetToFunction(var, class_name, flags); + +    String *mname_get = NewString("Get"); +    Append(mname_get, mname); + +    String *go_name = NewString("Get"); +    Append(go_name, var_name); + +    String *wname = Swig_name_wrapper(mname_get); +    Append(wname, unique_id); + +    int r = makeWrappers(var, go_name, NULL, wname, bases, NULL, vt, false); +    if (r != SWIG_OK) { +      return r; +    } + +    Delete(wname); +    Delete(mname_get); +    Delete(go_name); +    Delete(mname); +    Delete(var_name); +    Delete(var_type); +    Delete(vt); + +    Swig_restore(var); + +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * addFirstBaseInterface() +   * +   * When a C++ class uses multiple inheritance, we can use the C++ +   * pointer for the first base class but not for any subsequent base +   * classes.  However, the Go interface will match the interface for +   * all the base classes.  To avoid accidentally treating a class as +   * a pointer to a base class other than the first one, we use an +   * isClassname method.  This function adds those methods as +   * required. +   * +   * For convenience when using multiple inheritance, we also add +   * functions to retrieve the base class pointers. +   * ------------------------------------------------------------ */ + +  void addFirstBaseInterface(Node *n, Hash *parents, List *bases) { +    if (!bases || Len(bases) == 0) { +      return; +    } +    Iterator b = First(bases); +    if (!GetFlag(b.item, "feature:ignore")) { +      String *go_name = buildGoName(Getattr(n, "sym:name"), false, false); +      String *go_type_name = goCPointerType(Getattr(n, "classtypeobj"), true); +      String *go_base_name = exportedName(Getattr(b.item, "sym:name")); +      String *go_base_type = goType(n, Getattr(b.item, "classtypeobj")); +      String *go_base_type_name = goCPointerType(Getattr(b.item, "classtypeobj"), true); + +      Printv(f_go_wrappers, "func (p ", go_type_name, ") SwigIs", go_base_name, "() {\n", NULL); +      Printv(f_go_wrappers, "}\n\n", NULL); + +      Printv(interfaces, "\tSwigIs", go_base_name, "()\n", NULL); + +      Printv(f_go_wrappers, "func (p ", go_type_name, ") SwigGet", go_base_name, "() ", go_base_type, " {\n", NULL); +      Printv(f_go_wrappers, "\treturn ", go_base_type_name, "(getSwigcptr(p))\n", NULL); +      Printv(f_go_wrappers, "}\n\n", NULL); + +      Printv(interfaces, "\tSwigGet", go_base_name, "() ", go_base_type, "\n", NULL); + +      Setattr(parents, go_base_name, NewString("")); + +      Delete(go_name); +      Delete(go_type_name); +      Delete(go_base_type); +      Delete(go_base_type_name); +    } + +    addFirstBaseInterface(n, parents, Getattr(b.item, "bases")); +  } + +  /* ------------------------------------------------------------ +   * addExtraBaseInterfaces() +   * +   * Add functions to retrieve the base class pointers for all base +   * classes other than the first. +   * ------------------------------------------------------------ */ + +  int addExtraBaseInterfaces(Node *n, Hash *parents, List *bases) { +    Iterator b = First(bases); + +    Node *fb = b.item; + +    for (b = Next(b); b.item; b = Next(b)) { +      if (GetFlag(b.item, "feature:ignore")) { +	continue; +      } + +      String *go_base_name = exportedName(Getattr(b.item, "sym:name")); + +      Swig_save("addExtraBaseInterface", n, "wrap:action", "wrap:name", "wrap:parms", NULL); + +      SwigType *type = Copy(Getattr(n, "classtypeobj")); +      SwigType_add_pointer(type); +      Parm *parm = NewParm(type, "self", n); +      Setattr(n, "wrap:parms", parm); + +      String *pn = Swig_cparm_name(parm, 0); +      String *action = NewString(""); +      Printv(action, Swig_cresult_name(), " = (", Getattr(b.item, "classtype"), "*)", pn, ";", NULL); +      Delete(pn); + +      Setattr(n, "wrap:action", action); + +      String *name = Copy(class_name); +      Append(name, "_SwigGet"); +      Append(name, go_base_name); + +      String *go_name = NewString("SwigGet"); +      String *c1 = exportedName(go_base_name); +      Append(go_name, c1); +      Delete(c1); + +      String *wname = Swig_name_wrapper(name); +      Append(wname, unique_id); +      Setattr(n, "wrap:name", wname); + +      SwigType *result = Copy(Getattr(b.item, "classtypeobj")); +      SwigType_add_pointer(result); + +      int r = makeWrappers(n, go_name, NULL, wname, NULL, parm, result, false); +      if (r != SWIG_OK) { +	return r; +      } + +      Swig_restore(n); + +      Setattr(parents, go_base_name, NewString("")); + +      Delete(go_name); +      Delete(type); +      Delete(parm); +      Delete(action); +      Delete(result); + +      String *ns = NewString(""); +      addParentExtraBaseInterfaces(n, parents, b.item, false, ns); +      Delete(ns); +    } + +    if (!GetFlag(fb, "feature:ignore")) { +      String *ns = NewString(""); +      addParentExtraBaseInterfaces(n, parents, fb, true, ns); +      Delete(ns); +    } + +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * addParentExtraBaseInterfaces() +   * +   * Add functions to retrieve the base class pointers for all base +   * classes of parents other than the first base class at each level. +   * ------------------------------------------------------------ */ + +  void addParentExtraBaseInterfaces(Node *n, Hash *parents, Node *base, bool is_base_first, String *sofar) { +    List *baselist = Getattr(base, "bases"); +    if (!baselist || Len(baselist) == 0) { +      return; +    } + +    String *go_this_base_name = exportedName(Getattr(base, "sym:name")); + +    String *sf = NewString(""); +    Printv(sf, sofar, ".SwigGet", go_this_base_name, "()", NULL); + +    Iterator b = First(baselist); + +    if (is_base_first) { +      if (!b.item) { +	return; +      } +      if (!GetFlag(b.item, "feature:ignore")) { +	addParentExtraBaseInterfaces(n, parents, b.item, true, sf); +      } + +      b = Next(b); +    } + +    String *go_name = buildGoName(Getattr(n, "sym:name"), false, false); +    String *go_type_name = goCPointerType(Getattr(n, "classtypeobj"), true); + +    for (; b.item; b = Next(b)) { +      if (GetFlag(b.item, "feature:ignore")) { +	continue; +      } + +      String *go_base_name = exportedName(Getattr(b.item, "sym:name")); + +      if (!Getattr(parents, go_base_name)) { +	Printv(f_go_wrappers, "func (p ", go_type_name, ") SwigGet", go_base_name, "() ", go_base_name, " {\n", NULL); +	Printv(f_go_wrappers, "\treturn p", sf, ".SwigGet", go_base_name, "()\n", NULL); +	Printv(f_go_wrappers, "}\n\n", NULL); + +	Printv(interfaces, "\tSwigGet", go_base_name, "() ", go_base_name, "\n", NULL); + +	addParentExtraBaseInterfaces(n, parents, b.item, false, sf); + +	Setattr(parents, go_base_name, NewString("")); +      } +    } + +    Delete(go_name); +    Delete(go_type_name); +    Delete(go_this_base_name); +    Delete(sf); +  } + +  /* ------------------------------------------------------------ +   * classDirectorInit +   * +   * Add support for a director class. +   * +   * Virtual inheritance is different in Go and C++.  We implement +   * director classes by defining a new function in Go, +   * NewDirectorClassname, which takes a empty interface value and +   * creates an instance of a new child class.  The new child class +   * refers all methods back to Go.  The Go code checks whether the +   * value passed to NewDirectorClassname implements that method; if +   * it does, it calls it, otherwise it calls back into C++. +   * ------------------------------------------------------------ */ + +  int classDirectorInit(Node *n) { +    // Because we use a different function to handle inheritance in +    // Go, ordinary creations of the object should not create a +    // director object. +    Delete(director_ctor_code); +    director_ctor_code = NewString("$nondirector_new"); + +    class_node = n; + +    String *name = Getattr(n, "sym:name"); + +    assert(!class_name); +    class_name = name; + +    String *go_name = exportedName(name); + +    String *go_type_name = goCPointerType(Getattr(n, "classtypeobj"), true); + +    assert(!class_receiver); +    class_receiver = go_type_name; + +    String *director_struct_name = NewString("_swig_Director"); +    Append(director_struct_name, go_name); + +    String *cxx_director_name = NewString("SwigDirector_"); +    Append(cxx_director_name, name); + +    // The Go type of the director class. +    Printv(f_go_wrappers, "type ", director_struct_name, " struct {\n", NULL); +    Printv(f_go_wrappers, "\t", go_type_name, "\n", NULL); +    Printv(f_go_wrappers, "\tv interface{}\n", NULL); +    Printv(f_go_wrappers, "}\n\n", NULL); + +    Printv(f_go_wrappers, "func (p *", director_struct_name, ") Swigcptr() uintptr {\n", NULL); +    Printv(f_go_wrappers, "\treturn getSwigcptr(p.", go_type_name, ")\n", NULL); +    Printv(f_go_wrappers, "}\n\n", NULL); + +    Printv(f_go_wrappers, "func (p *", director_struct_name, ") SwigIs", go_name, "() {\n", NULL); +    Printv(f_go_wrappers, "}\n\n", NULL); + +    Printv(f_go_wrappers, "func (p *", director_struct_name, ") DirectorInterface() interface{} {\n", NULL); +    Printv(f_go_wrappers, "\treturn p.v\n", NULL); +    Printv(f_go_wrappers, "}\n\n", NULL); + +    // Start defining the director class. +    Printv(f_c_directors_h, "class ", cxx_director_name, " : public ", Getattr(n, "classtype"), "\n", NULL); +    Printv(f_c_directors_h, "{\n", NULL); +    Printv(f_c_directors_h, " public:\n", NULL); + +    Delete(director_struct_name); +    Delete(cxx_director_name); + +    class_methods = NewHash(); + +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * classDirectorConstructor +   * +   * Emit a constructor for a director class. +   * ------------------------------------------------------------ */ + +  int classDirectorConstructor(Node *n) { +    bool is_ignored = GetFlag(n, "feature:ignore") ? true : false; + +    String *name = Getattr(n, "sym:name"); +    if (!name) { +      assert(is_ignored); +      name = Getattr(n, "name"); +    } + +    String *overname = NULL; +    if (Getattr(n, "sym:overloaded")) { +      overname = Getattr(n, "sym:overname"); +    } + +    String *go_name = exportedName(name); + +    ParmList *parms = Getattr(n, "parms"); +    Setattr(n, "wrap:parms", parms); + +    String *cn = exportedName(Getattr(parentNode(n), "sym:name")); + +    String *go_type_name = goCPointerType(Getattr(parentNode(n), "classtypeobj"), true); + +    String *director_struct_name = NewString("_swig_Director"); +    Append(director_struct_name, cn); + +    String *fn_name = NewString("_swig_NewDirector"); +    Append(fn_name, cn); +    Append(fn_name, go_name); + +    if (!overname && !is_ignored) { +      if (!checkNameConflict(fn_name, n, NULL)) { +	return SWIG_NOWRAP; +      } +    } + +    String *fn_with_over_name = Copy(fn_name); +    if (overname) { +      Append(fn_with_over_name, overname); +    } + +    String *wname = Swig_name_wrapper(fn_name); + +    if (overname) { +      Append(wname, overname); +    } +    Append(wname, unique_id); +    Setattr(n, "wrap:name", wname); + +    bool is_static = isStatic(n); + +    Wrapper *dummy = NewWrapper(); +    emit_attach_parmmaps(parms, dummy); +    DelWrapper(dummy); + +    Swig_typemap_attach_parms("gotype", parms, NULL); +    Swig_typemap_attach_parms("goin", parms, NULL); +    Swig_typemap_attach_parms("goargout", parms, NULL); +    Swig_typemap_attach_parms("imtype", parms, NULL); +    int parm_count = emit_num_arguments(parms); + +    String *func_name = NewString("NewDirector"); +    Append(func_name, go_name); + +    String *func_with_over_name = Copy(func_name); +    if (overname) { +      Append(func_with_over_name, overname); +    } + +    SwigType *first_type = NewString("int"); +    Parm *first_parm = NewParm(first_type, "swig_p", n); +    set_nextSibling(first_parm, parms); +    Setattr(first_parm, "lname", "p"); + +    Parm *p = parms; +    for (int i = 0; i < parm_count; ++i) { +      p = getParm(p); +      Swig_cparm_name(p, i); +      p = nextParm(p); +    } + +    if (!is_ignored) { +      Printv(f_cgo_comment, "extern uintptr_t ", wname, "(int", NULL); + +      p = parms; +      for (int i = 0; i < parm_count; ++i) { +	p = getParm(p); +	bool c_struct_type; +	String *ct = cgoTypeForGoValue(p, Getattr(p, "type"), &c_struct_type); +	Printv(f_cgo_comment, ", ", ct, " ", Getattr(p, "lname"), NULL); +	p = nextParm(p); +      } +      Printv(f_cgo_comment, ");\n", NULL); + +      // Write out the Go function that calls the wrapper. + +      Printv(f_go_wrappers, "func ", func_with_over_name, "(v interface{}", NULL); + +      p = parms; +      for (int i = 0; i < parm_count; ++i) { +	p = getParm(p); +	Printv(f_go_wrappers, ", ", Getattr(p, "lname"), " ", NULL); +	String *tm = goType(p, Getattr(p, "type")); +	Printv(f_go_wrappers, tm, NULL); +	Delete(tm); +	p = nextParm(p); +      } + +      Printv(f_go_wrappers, ") ", cn, " {\n", NULL); + +      Printv(f_go_wrappers, "\tp := &", director_struct_name, "{0, v}\n", NULL); + +      String *call = NewString(""); + +      Printv(call, "\tp.", class_receiver, " = ", NULL); +      Printv(call, go_type_name, "(C.", wname, "(C.int(swigDirectorAdd(p))", NULL); + +      p = parms; +      for (int i = 0; i < parm_count; ++i) { +	Printv(call, ", ", NULL); + +	p = getParm(p); +	String *pt = Getattr(p, "type"); +	String *ln = Getattr(p, "lname"); + +	String *ivar = NewStringf("_swig_i_%d", i); + +	String *goin = goGetattr(p, "tmap:goin"); +	if (goin == NULL) { +	  Printv(f_go_wrappers, "\t", ivar, " := ", NULL); +	  bool need_close = false; +	  if (goTypeIsInterface(p, pt)) { +	    Printv(f_go_wrappers, "getSwigcptr(", NULL); +	    need_close = true; +	  } +	  Printv(f_go_wrappers, ln, NULL); +	  if (need_close) { +	    Printv(f_go_wrappers, ")", NULL); +	  } +	  Printv(f_go_wrappers, "\n", NULL); +	} else { +	  String *itm = goImType(p, pt); +	  Printv(f_go_wrappers, "\tvar ", ivar, " ", itm, "\n", NULL); +	  goin = Copy(goin); +	  Replaceall(goin, "$input", ln); +	  Replaceall(goin, "$result", ivar); +	  Printv(f_go_wrappers, goin, "\n", NULL); +	  Delete(goin); +	} + +	Setattr(p, "emit:goinput", ivar); + +	bool c_struct_type; +	String *ct = cgoTypeForGoValue(p, pt, &c_struct_type); +	if (c_struct_type) { +	  Printv(call, "*(*C.", ct, ")(unsafe.Pointer(&", ivar, "))", NULL); +	} else { +	  Printv(call, "C.", ct, "(", ivar, ")", NULL); +	} +	Delete(ct); + +	p = nextParm(p); +      } + +      Printv(call, "))", NULL); + +      Printv(f_go_wrappers, call, "\n", NULL); + +      goargout(parms); + +      Printv(f_go_wrappers, "\treturn p\n", NULL); +      Printv(f_go_wrappers, "}\n\n", NULL); + +      SwigType *result = Copy(Getattr(parentNode(n), "classtypeobj")); +      SwigType_add_pointer(result); + +      Swig_save("classDirectorConstructor", n, "wrap:name", "wrap:action", NULL); + +      String *dwname = Swig_name_wrapper(name); +      Append(dwname, unique_id); +      Setattr(n, "wrap:name", dwname); + +      String *action = NewString(""); +      Printv(action, Swig_cresult_name(), " = new SwigDirector_", class_name, "(", NULL); +      String *pname = Swig_cparm_name(NULL, 0); +      Printv(action, pname, NULL); +      Delete(pname); +      p = parms; +      for (int i = 0; i < parm_count; ++i) { +	p = getParm(p); +	String *pname = Swig_cparm_name(NULL, i + 1); +	Printv(action, ", ", NULL); +	if (SwigType_isreference(Getattr(p, "type"))) { +	  Printv(action, "*", NULL); +	} +	Printv(action, pname, NULL); +	Delete(pname); +	p = nextParm(p); +      } +      Printv(action, ");", NULL); +      Setattr(n, "wrap:action", action); + +      cgoWrapperInfo info; + +      info.n = n; +      info.go_name = func_name; +      info.overname = overname; +      info.wname = wname; +      info.base = NULL; +      info.parms = first_parm; +      info.result = result; +      info.is_static = false; +      info.receiver = NULL; +      info.is_constructor = true; +      info.is_destructor = false; + +      int r = cgoGccWrapper(&info); +      if (r != SWIG_OK) { +	return r; +      } + +      Swig_restore(n); + +      Delete(result); +    } + +    String *cxx_director_name = NewString("SwigDirector_"); +    Append(cxx_director_name, class_name); + +    String *decl = Swig_method_decl(NULL, Getattr(n, "decl"), cxx_director_name, first_parm, 0); +    Printv(f_c_directors_h, "  ", decl, ";\n", NULL); +    Delete(decl); + +    decl = Swig_method_decl(NULL, Getattr(n, "decl"), cxx_director_name, first_parm, 0); +    Printv(f_c_directors, cxx_director_name, "::", decl, "\n", NULL); +    Delete(decl); + +    Printv(f_c_directors, "    : ", Getattr(parentNode(n), "classtype"), "(", NULL); + +    p = parms; +    for (int i = 0; i < parm_count; ++i) { +      p = getParm(p); +      if (i > 0) { +	Printv(f_c_directors, ", ", NULL); +      } +      String *pn = Getattr(p, "name"); +      assert(pn); +      Printv(f_c_directors, pn, NULL); +      p = nextParm(p); +    } +    Printv(f_c_directors, "),\n", NULL); +    Printv(f_c_directors, "      go_val(swig_p), swig_mem(0)\n", NULL); +    Printv(f_c_directors, "{ }\n\n", NULL); + +    if (Getattr(n, "sym:overloaded") && !Getattr(n, "sym:nextSibling")) { +      int r = makeDispatchFunction(n, func_name, cn, is_static, Getattr(parentNode(n), "classtypeobj"), false); +      if (r != SWIG_OK) { +	return r; +      } +    } + +    Delete(cxx_director_name); +    Delete(go_name); +    Delete(cn); +    Delete(go_type_name); +    Delete(director_struct_name); +    Delete(fn_name); +    Delete(fn_with_over_name); +    Delete(func_name); +    Delete(func_with_over_name); +    Delete(wname); +    Delete(first_type); +    Delete(first_parm); + +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * classDirectorDestructor +   * +   * Emit a destructor for a director class. +   * ------------------------------------------------------------ */ + +  int classDirectorDestructor(Node *n) { +    if (!is_public(n)) { +      return SWIG_OK; +    } + +    bool is_ignored = GetFlag(n, "feature:ignore") ? true : false; + +    if (!is_ignored) { +      String *fnname = NewString("DeleteDirector"); +      String *c1 = exportedName(class_name); +      Append(fnname, c1); +      Delete(c1); + +      String *wname = Swig_name_wrapper(fnname); +      Append(wname, unique_id); + +      Setattr(n, "wrap:name", fnname); + +      Swig_DestructorToFunction(n, getNSpace(), getClassType(), CPlusPlus, Extend); + +      ParmList *parms = Getattr(n, "parms"); +      Setattr(n, "wrap:parms", parms); + +      String *result = NewString("void"); +      int r = makeWrappers(n, fnname, NULL, wname, NULL, parms, result, isStatic(n)); +      if (r != SWIG_OK) { +	return r; +      } + +      Delete(result); +      Delete(fnname); +      Delete(wname); +    } + +    // Generate the destructor for the C++ director class.  Since the +    // Go code is keeping a pointer to the C++ object, we need to call +    // back to the Go code to let it know that the C++ object is gone. + +    String *go_name = NewString("Swiggo_DeleteDirector_"); +    Append(go_name, class_name); + +    String *cn = exportedName(class_name); + +    String *director_struct_name = NewString("_swig_Director"); +    Append(director_struct_name, cn); + +    Printv(f_c_directors_h, "  virtual ~SwigDirector_", class_name, "()", NULL); + +    String *throws = buildThrow(n); +    if (throws) { +      Printv(f_c_directors_h, " ", throws, NULL); +    } + +    Printv(f_c_directors_h, ";\n", NULL); + +    String *director_sig = NewString(""); + +    Printv(director_sig, "SwigDirector_", class_name, "::~SwigDirector_", class_name, "()", NULL); + +    if (throws) { +      Printv(director_sig, " ", throws, NULL); +      Delete(throws); +    } + +    Printv(director_sig, "\n", NULL); +    Printv(director_sig, "{\n", NULL); + +    if (is_ignored) { +      Printv(f_c_directors, director_sig, NULL); +    } else { +      makeDirectorDestructorWrapper(go_name, director_struct_name, director_sig); +    } + +    Printv(f_c_directors, "  delete swig_mem;\n", NULL); + +    Printv(f_c_directors, "}\n\n", NULL); + +    Delete(director_sig); +    Delete(go_name); +    Delete(cn); +    Delete(director_struct_name); + +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * makeDirectorDestructorWrapper +   * +   * Emit the function wrapper for the destructor of a director class. +   * ------------------------------------------------------------ */ + +  void makeDirectorDestructorWrapper(String *go_name, String *director_struct_name, String *director_sig) { +    String *wname = Copy(go_name); +    Append(wname, unique_id); + +    Printv(f_go_wrappers, "//export ", wname, "\n", NULL); +    Printv(f_go_wrappers, "func ", wname, "(c int) {\n", NULL); +    Printv(f_go_wrappers, "\tswigDirectorLookup(c).(*", director_struct_name, ").", class_receiver, " = 0\n", NULL); +    Printv(f_go_wrappers, "\tswigDirectorDelete(c)\n", NULL); +    Printv(f_go_wrappers, "}\n\n", NULL); + +    Printv(f_c_directors, "extern \"C\" void ", wname, "(intgo);\n", NULL); +    Printv(f_c_directors, director_sig, NULL); +    Printv(f_c_directors, "  ", wname, "(go_val);\n", NULL); +  } + +  /* ------------------------------------------------------------ +   * classDirectorMethod +   * +   * Emit a method for a director class, plus its overloads. +   * ------------------------------------------------------------ */ + +  int classDirectorMethod(Node *n, Node *parent, String *super) { +    bool is_ignored = GetFlag(n, "feature:ignore") ? true : false; + +    // We don't need explicit calls. +    if (GetFlag(n, "explicitcall")) { +      return SWIG_OK; +    } + +    String *name = Getattr(n, "sym:name"); +    if (!name) { +      assert(is_ignored); +      (void)is_ignored; +      name = Getattr(n, "name"); +    } + +    bool overloaded = Getattr(n, "sym:overloaded") && !Getattr(n, "explicitcallnode"); +    if (!overloaded) { +      int r = oneClassDirectorMethod(n, parent, super); +      if (r != SWIG_OK) { +	return r; +      } +    } else { +      // Handle overloaded methods here, because otherwise we will +      // reject them in the class_methods hash table.  We need to use +      // class_methods so that we correctly handle cases where a +      // function in one class hides a function of the same name in a +      // parent class. +      if (!Getattr(class_methods, name)) { +	for (Node *on = Getattr(n, "sym:overloaded"); on; on = Getattr(on, "sym:nextSibling")) { +	  // Swig_overload_rank expects wrap:name and wrap:parms to be +	  // set. +	  String *wn = Swig_name_wrapper(Getattr(on, "sym:name")); +	  Append(wn, Getattr(on, "sym:overname")); +	  Append(wn, unique_id); +	  Setattr(on, "wrap:name", wn); +	  Delete(wn); +	  Setattr(on, "wrap:parms", Getattr(on, "parms")); +	} +      } + +      int r = oneClassDirectorMethod(n, parent, super); +      if (r != SWIG_OK) { +	return r; +      } + +      if (!Getattr(n, "sym:nextSibling")) +      { +	// Last overloaded function +	Node *on = Getattr(n, "sym:overloaded"); +	bool is_static = isStatic(on); + +	String *cn = exportedName(Getattr(parent, "sym:name")); +	String *go_name = buildGoName(name, is_static, false); + +	String *director_struct_name = NewString("_swig_Director"); +	Append(director_struct_name, cn); + +	int r = makeDispatchFunction(on, go_name, director_struct_name, is_static, director_struct_name, false); +	if (r != SWIG_OK) { +	  return r; +	} + +	if (!GetFlag(n, "abstract")) { +	  String *go_upcall = NewString("Director"); +	  Append(go_upcall, cn); +	  Append(go_upcall, go_name); +	  r = makeDispatchFunction(on, go_upcall, director_struct_name, is_static, director_struct_name, true); +	  if (r != SWIG_OK) { +	    return r; +	  } +	  Delete(go_upcall); +	} + +	Delete(director_struct_name); +	Delete(go_name); +	Delete(cn); +      } +    } +    Setattr(class_methods, name, NewString("")); + +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * oneClassDirectorMethod +   * +   * Emit a method for a director class. +   * ------------------------------------------------------------ */ + +  int oneClassDirectorMethod(Node *n, Node *parent, String *super) { +    String *symname = Getattr(n, "sym:name"); +    if (!checkFunctionVisibility(n, parent)) { +      return SWIG_OK; +    } + +    bool is_ignored = GetFlag(n, "feature:ignore") ? true : false; +    bool is_pure_virtual = (Cmp(Getattr(n, "storage"), "virtual") == 0 && Cmp(Getattr(n, "value"), "0") == 0); + +    String *name = Getattr(n, "sym:name"); +    if (!name) { +      assert(is_ignored); +      name = Getattr(n, "name"); +    } + +    String *overname = NULL; +    if (Getattr(n, "sym:overloaded")) { +      overname = Getattr(n, "sym:overname"); +    } + +    String *cn = exportedName(Getattr(parent, "sym:name")); + +    String *go_type_name = goCPointerType(Getattr(parent, "classtypeobj"), true); + +    String *director_struct_name = NewString("_swig_Director"); +    Append(director_struct_name, cn); + +    bool is_static = isStatic(n); + +    String *go_name = buildGoName(name, is_static, false); + +    ParmList *parms = Getattr(n, "parms"); +    Setattr(n, "wrap:parms", parms); + +    Wrapper *dummy = NewWrapper(); +    emit_attach_parmmaps(parms, dummy); + +    Swig_typemap_attach_parms("gotype", parms, NULL); +    Swig_typemap_attach_parms("imtype", parms, NULL); +    int parm_count = emit_num_arguments(parms); + +    SwigType *result = Getattr(n, "type"); + +    // Save the type for overload processing. +    Setattr(n, "go:type", result); + +    String *interface_name = NewString("_swig_DirectorInterface"); +    Append(interface_name, cn); +    Append(interface_name, go_name); +    if (overname) { +      Append(interface_name, overname); +    } + +    String *callback_name = Copy(director_struct_name); +    Append(callback_name, "_callback_"); +    Append(callback_name, name); +    Replace(callback_name, "_swig", "Swig", DOH_REPLACE_FIRST); +    if (overname) { +      Append(callback_name, overname); +    } +    Append(callback_name, unique_id); + +    String *upcall_name = Copy(director_struct_name); +    Append(upcall_name, "_upcall_"); +    Append(upcall_name, go_name); + +    String *upcall_wname = Swig_name_wrapper(upcall_name); +    if (overname) { +      Append(upcall_wname, overname); +    } +    Append(upcall_wname, unique_id); + +    String *upcall_gc_name = buildGoWrapperName(upcall_name, overname); + +    String *go_with_over_name = Copy(go_name); +    if (overname) { +      Append(go_with_over_name, overname); +    } + +    Parm *p = 0; +    Wrapper *w = NewWrapper(); + +    Swig_director_parms_fixup(parms); + +    Swig_typemap_attach_parms("directorin", parms, w); +    Swig_typemap_attach_parms("directorargout", parms, w); +    Swig_typemap_attach_parms("godirectorin", parms, w); +    Swig_typemap_attach_parms("goin", parms, dummy); +    Swig_typemap_attach_parms("goargout", parms, dummy); + +    DelWrapper(dummy); + +    if (!is_ignored) { +      // We use an interface to see if this method is defined in Go. +      Printv(f_go_wrappers, "type ", interface_name, " interface {\n", NULL); +      Printv(f_go_wrappers, "\t", go_with_over_name, "(", NULL); + +      p = parms; +      for (int i = 0; i < parm_count; ++i) { +	p = getParm(p); +	if (i > 0) { +	  Printv(f_go_wrappers, ", ", NULL); +	} +	String *tm = goType(p, Getattr(p, "type")); +	Printv(f_go_wrappers, tm, NULL); +	Delete(tm); +	p = nextParm(p); +      } + +      Printv(f_go_wrappers, ")", NULL); + +      if (SwigType_type(result) != T_VOID) { +	String *tm = goType(n, result); +	Printv(f_go_wrappers, " ", tm, NULL); +	Delete(tm); +      } + +      Printv(f_go_wrappers, "\n", NULL); +      Printv(f_go_wrappers, "}\n\n", NULL); + +      if (!GetFlag(n, "abstract")) { +	Printv(f_cgo_comment, "extern ", NULL); + +	if (SwigType_type(result) == T_VOID) { +	  Printv(f_cgo_comment, "void", NULL); +	} else { +	  bool c_struct_type; +	  String *ret_type = cgoTypeForGoValue(n, result, &c_struct_type); +	  Printv(f_cgo_comment, ret_type, NULL); +	  Delete(ret_type); +	} + +	Printv(f_cgo_comment, " ", upcall_wname, "(uintptr_t", NULL); + +	p = parms; +	for (int i = 0; i < parm_count; ++i) { +	  p = getParm(p); +	  bool c_struct_type; +	  String *ct = cgoTypeForGoValue(p, Getattr(p, "type"), &c_struct_type); +	  Printv(f_cgo_comment, ", ", ct, " ", Getattr(p, "lname"), NULL); +	  p = nextParm(p); +	} +	Printv(f_cgo_comment, ");\n", NULL); +      } + +      // Define the method on the director class in Go. + +      Printv(f_go_wrappers, "func (swig_p *", director_struct_name, ") ", go_with_over_name, "(", NULL); + +      p = parms; +      for (int i = 0; i < parm_count; ++i) { +	p = getParm(p); +	if (i > 0) { +	  Printv(f_go_wrappers, ", ", NULL); +	} +	Printv(f_go_wrappers, Getattr(p, "lname"), " ", NULL); +	String *tm = goType(p, Getattr(p, "type")); +	Printv(f_go_wrappers, tm, NULL); +	Delete(tm); +	p = nextParm(p); +      } + +      Printv(f_go_wrappers, ")", NULL); + +      if (SwigType_type(result) != T_VOID) { +	String *tm = goType(n, result); +	Printv(f_go_wrappers, " ", tm, NULL); +	Delete(tm); +      } + +      Printv(f_go_wrappers, " {\n", NULL); + +      Printv(f_go_wrappers, "\tif swig_g, swig_ok := swig_p.v.(", interface_name, "); swig_ok {\n", NULL); +      Printv(f_go_wrappers, "\t\t", NULL); +      if (SwigType_type(result) != T_VOID) { +	Printv(f_go_wrappers, "return ", NULL); +      } +      Printv(f_go_wrappers, "swig_g.", go_with_over_name, "(", NULL); + +      p = parms; +      for (int i = 0; i < parm_count; ++i) { +	p = getParm(p); +	if (i > 0) { +	  Printv(f_go_wrappers, ", ", NULL); +	} +	Printv(f_go_wrappers, Getattr(p, "lname"), NULL); +	p = nextParm(p); +      } + +      Printv(f_go_wrappers, ")\n", NULL); +      if (SwigType_type(result) == T_VOID) { +	Printv(f_go_wrappers, "\t\treturn\n", NULL); +      } +      Printv(f_go_wrappers, "\t}\n", NULL); + +      if (GetFlag(n, "abstract")) { +	Printv(f_go_wrappers, "\tpanic(\"call to pure virtual method\")\n", NULL); +      } else { +	String *ret_type = NULL; +	bool memcpy_ret = false; +	String *wt = NULL; +	String *goout = NULL; +	if (SwigType_type(result) != T_VOID) { +	  ret_type = goImType(n, result); +	  Printv(f_go_wrappers, "\tvar swig_r ", ret_type, "\n", NULL); +	  goout = goTypemapLookup("goout", n, "swig_r"); + +	  bool c_struct_type; +	  Delete(cgoTypeForGoValue(n, result, &c_struct_type)); +	  if (c_struct_type) { +	    memcpy_ret = true; +	  } +	} + +	String *call = NewString(""); + +	Printv(call, "\t", NULL); +	if (SwigType_type(result) != T_VOID) { +	  if (memcpy_ret) { +	    Printv(call, "swig_r_p := ", NULL); +	  } else { +	    Printv(call, "swig_r = (", ret_type, ")(", NULL); +	  } +	  if (goTypeIsInterface(n, result)) { +	    wt = goWrapperType(n, result, true); +	    Printv(call, "(", wt, ")(", NULL); +	  } +	} + +	Printv(call, "C.", upcall_wname, "(C.uintptr_t(swig_p.", +	       go_type_name, ")", NULL); + +	p = parms; +	for (int i = 0; i < parm_count; ++i) { +	  Printv(call, ", ", NULL); +	  p = getParm(p); +	  SwigType *pt = Getattr(p, "type"); + +	  String *ln = Getattr(p, "lname"); + +	  String *ivar = NewStringf("_swig_i_%d", i); + +	  // This is an ordinary call from Go to C++, so adjust using +	  // the goin typemap. +	  String *goin = goGetattr(p, "tmap:goin"); +	  if (goin == NULL) { +	    Printv(f_go_wrappers, "\t", ivar, " := ", NULL); +	    bool need_close = false; +	    if (goTypeIsInterface(p, pt)) { +	      Printv(f_go_wrappers, "getSwigcptr(", NULL); +	      need_close = true; +	    } +	    Printv(f_go_wrappers, ln, NULL); +	    if (need_close) { +	      Printv(f_go_wrappers, ")", NULL); +	    } +	    Printv(f_go_wrappers, "\n", NULL); +	  } else { +	    String *itm = goImType(p, pt); +	    Printv(f_go_wrappers, "\tvar ", ivar, " ", itm, "\n", NULL); +	    goin = Copy(goin); +	    Replaceall(goin, "$input", ln); +	    Replaceall(goin, "$result", ivar); +	    Printv(f_go_wrappers, goin, "\n", NULL); +	    Delete(goin); +	  } + +	  Setattr(p, "emit:goinput", ivar); + +	  bool c_struct_type; +	  String *ct = cgoTypeForGoValue(p, pt, &c_struct_type); +	  if (c_struct_type) { +	    Printv(call, "*(*C.", ct, ")(unsafe.Pointer(&", ivar, "))", NULL); +	  } else { +	    Printv(call, "C.", ct, "(", ivar, ")", NULL); +	  } + +	  p = nextParm(p); +	} + +	Printv(call, ")", NULL); + +	if (wt) { +	  // Close the type conversion to the wrapper type. +	  Printv(call, ")", NULL); +	} +	if (SwigType_type(result) != T_VOID && !memcpy_ret) { +	  // Close the type conversion of the return value. +	  Printv(call, ")", NULL); +	} + +	Printv(call, "\n", NULL); + +	Printv(f_go_wrappers, call, NULL); +	Delete(call); + +	if (memcpy_ret) { +	  Printv(f_go_wrappers, "\tswig_r = *(*", ret_type, ")(unsafe.Pointer(&swig_r_p))\n", NULL); +	} + +	goargout(parms); + +	if (SwigType_type(result) != T_VOID) { +	  if (goout == NULL) { +	    Printv(f_go_wrappers, "\treturn swig_r\n", NULL); +	  } else { +	    String *tm = goType(n, result); +	    Printv(f_go_wrappers, "\tvar swig_r_1 ", tm, "\n", NULL); +	    Replaceall(goout, "$input", "swig_r"); +	    Replaceall(goout, "$result", "swig_r_1"); +	    Printv(f_go_wrappers, goout, "\n", NULL); +	    Printv(f_go_wrappers, "\treturn swig_r_1\n", NULL); +	  } +	} + +	if (ret_type) { +	  Delete(ret_type); +	} +	if (wt) { +	  Delete(wt); +	} +      } + +      Printv(f_go_wrappers, "}\n\n", NULL); + +      if (!GetFlag(n, "abstract")) { +	// Define a function that uses the Go director type that other +	// methods in the Go type can call to get parent methods. + +	Printv(f_go_wrappers, "func Director", cn, go_with_over_name, "(swig_p ", cn, NULL); + +	p = parms; +	for (int i = 0; i < parm_count; ++i) { +	  p = getParm(p); +	  Printv(f_go_wrappers, ", ", Getattr(p, "lname"), " ", NULL); +	  String *tm = goType(p, Getattr(p, "type")); +	  Printv(f_go_wrappers, tm, NULL); +	  Delete(tm); +	  p = nextParm(p); +	} + +	Printv(f_go_wrappers, ")", NULL); + +	if (SwigType_type(result) != T_VOID) { +	  String *tm = goType(n, result); +	  Printv(f_go_wrappers, " ", tm, NULL); +	  Delete(tm); +	} + +	Printv(f_go_wrappers, " {\n", NULL); + +	String *ret_type = NULL; +	bool memcpy_ret = false; +	String *wt = NULL; +	String *goout = NULL; +	if (SwigType_type(result) != T_VOID) { +	  ret_type = goImType(n, result); +	  Printv(f_go_wrappers, "\tvar swig_r ", ret_type, "\n", NULL); +	  goout = goTypemapLookup("goout", n, "swig_r"); + +	  bool c_struct_type; +	  Delete(cgoTypeForGoValue(n, result, &c_struct_type)); +	  if (c_struct_type) { +	    memcpy_ret = true; +	  } +	} + +	String *call = NewString(""); + +	Printv(call, "\t", NULL); +	if (SwigType_type(result) != T_VOID) { +	  if (memcpy_ret) { +	    Printv(call, "swig_r_p := ", NULL); +	  } else { +	    Printv(call, "swig_r = (", ret_type, ")(", NULL); +	  } +	  if (goTypeIsInterface(n, result)) { +	    wt = goWrapperType(n, result, true); +	    Printv(call, "(", wt, ")(", NULL); +	  } +	} + +	Printv(call, "C.", upcall_wname, "(C.uintptr_t(swig_p.(*", +	       director_struct_name, ").", go_type_name, ")", NULL); + +	p = parms; +	for (int i = 0; i < parm_count; ++i) { +	  Printv(call, ", ", NULL); +	  p = getParm(p); +	  SwigType *pt = Getattr(p, "type"); + +	  String *ivar = NewStringf("_swig_i_%d", i); + +	  String *ln = Copy(Getattr(p, "lname")); + +	  String *goin = goGetattr(p, "tmap:goin"); +	  if (goin == NULL) { +	    Printv(f_go_wrappers, "\t", ivar, " := ", NULL); +	    bool need_close = false; +	    if (goTypeIsInterface(p, pt)) { +	      Printv(f_go_wrappers, "getSwigcptr(", NULL); +	      need_close = true; +	    } +	    Printv(f_go_wrappers, ln, NULL); +	    if (need_close) { +	      Printv(f_go_wrappers, ")", NULL); +	    } +	    Printv(f_go_wrappers, "\n", NULL); +	  } else { +	    String *itm = goImType(p, pt); +	    Printv(f_go_wrappers, "\tvar ", ivar, " ", itm, "\n", NULL); +	    goin = Copy(goin); +	    Replaceall(goin, "$input", ln); +	    Replaceall(goin, "$result", ivar); +	    Printv(f_go_wrappers, goin, "\n", NULL); +	    Delete(goin); +	  } + +	  Setattr(p, "emit:goinput", ivar); + +	  bool c_struct_type; +	  String *ct = cgoTypeForGoValue(p, pt, &c_struct_type); +	  if (c_struct_type) { +	    Printv(call, "*(*C.", ct, ")(unsafe.Pointer(&", ivar, "))", NULL); +	  } else { +	    Printv(call, "C.", ct, "(", ivar, ")", NULL); +	  } + +	  Delete(ln); + +	  p = nextParm(p); +	} + +	Printv(call, ")", NULL); + +	if (wt) { +	  // Close the type conversion to the wrapper type. +	  Printv(call, ")", NULL); +	} +	if (SwigType_type(result) != T_VOID && !memcpy_ret) { +	  // Close the type conversion of the return value. +	  Printv(call, ")", NULL); +	} + +	Printv(call, "\n", NULL); + +	Printv(f_go_wrappers, call, NULL); +	Delete(call); + +	if (memcpy_ret) { +	  Printv(f_go_wrappers, "\tswig_r = *(*", ret_type, ")(unsafe.Pointer(&swig_r_p))\n", NULL); +	} + +	goargout(parms); + +	if (SwigType_type(result) != T_VOID) { +	  if (goout == NULL) { +	    Printv(f_go_wrappers, "\treturn swig_r\n", NULL); +	  } else { +	    String *tm = goType(n, result); +	    Printv(f_go_wrappers, "\tvar swig_r_1 ", tm, "\n", NULL); +	    Replaceall(goout, "$input", "swig_r"); +	    Replaceall(goout, "$result", "swig_r_1"); +	    Printv(f_go_wrappers, goout, "\n", NULL); +	    Printv(f_go_wrappers, "\treturn swig_r_1\n", NULL); +	  } +	} + +	Printv(f_go_wrappers, "}\n\n", NULL); + +	if (ret_type) { +	  Delete(ret_type); +	} +	if (wt) { +	  Delete(wt); +	} + +	// Define a method in the C++ director class that the C++ +	// upcall function can call.  This permits an upcall to a +	// protected method. + +	String *upcall_method_name = NewString("_swig_upcall_"); +	Append(upcall_method_name, name); +	if (overname) { +	  Append(upcall_method_name, overname); +	} +	SwigType *rtype = Getattr(n, "classDirectorMethods:type"); +	String *upcall_decl = Swig_method_decl(rtype, Getattr(n, "decl"), upcall_method_name, parms, 0); +	Printv(f_c_directors_h, "  ", upcall_decl, " {\n", NULL); +	Delete(upcall_decl); + +	Printv(f_c_directors_h, "    ", NULL); +	if (SwigType_type(result) != T_VOID) { +	  Printv(f_c_directors_h, "return ", NULL); +	} + +	String *super_call = Swig_method_call(super, parms); +	Printv(f_c_directors_h, super_call, ";\n", NULL); +	Delete(super_call); + +	Printv(f_c_directors_h, "  }\n", NULL); + +	// Define the C++ function that the Go function calls. + +	SwigType *first_type = NULL; +	Parm *first_parm = parms; +	if (!is_static) { +	  first_type = NewString("SwigDirector_"); +	  Append(first_type, class_name); +	  SwigType_add_pointer(first_type); +	  first_parm = NewParm(first_type, "p", n); +	  set_nextSibling(first_parm, parms); +	} + +	Swig_save("classDirectorMethod", n, "wrap:name", "wrap:action", NULL); + +	Setattr(n, "wrap:name", upcall_wname); + +	String *action = NewString(""); +	if (SwigType_type(result) != T_VOID) { +	  Printv(action, Swig_cresult_name(), " = (", SwigType_lstr(result, 0), ")", NULL); +	  if (SwigType_isreference(result)) { +	    Printv(action, "&", NULL); +	  } +	} +	Printv(action, Swig_cparm_name(NULL, 0), "->", upcall_method_name, "(", NULL); + +	p = parms; +	int i = 0; +	while (p != NULL) { +	  if (SwigType_type(Getattr(p, "type")) != T_VOID) { +	    String *pname = Swig_cparm_name(NULL, i + 1); +	    if (i > 0) { +	      Printv(action, ", ", NULL); +	    } + +	    // A parameter whose type is a reference is converted into a +	    // pointer type by gcCTypeForGoValue.  We are calling a +	    // function which expects a reference so we need to convert +	    // back. +	    if (SwigType_isreference(Getattr(p, "type"))) { +	      Printv(action, "*", NULL); +	    } + +	    Printv(action, pname, NULL); +	    Delete(pname); +	    i++; +	  } +	  p = nextSibling(p); +	} +	Printv(action, ");", NULL); +	Setattr(n, "wrap:action", action); + +	cgoWrapperInfo info; + +	info.n = n; +	info.go_name = go_name; +	info.overname = overname; +	info.wname = upcall_wname; +	info.base = NULL; +	info.parms = first_parm; +	info.result = result; +	info.is_static = is_static; +	info.receiver = NULL; +	info.is_constructor = false; +	info.is_destructor = false; + +	int r = cgoGccWrapper(&info); +	if (r != SWIG_OK) { +	  return r; +	} + +	Delete(first_type); +	if (first_parm != parms) { +	  Delete(first_parm); +	} + +	Swig_restore(n); +	Delete(upcall_method_name); +      } + +      // The Go function which invokes the method.  This is called by +      // the C++ method on the director class. + +      Printv(f_go_wrappers, "//export ", callback_name, "\n", +	     "func ", callback_name, "(swig_c int", NULL); + +      p = parms; +      for (int i = 0; i < parm_count; ++i) { +	p = getParm(p); +	String *tm = goWrapperType(p, Getattr(p, "type"), false); +	Printv(f_go_wrappers, ", ", Getattr(p, "lname"), " ", tm, NULL); +	Delete(tm); +	p = nextParm(p); +      } + +      Printv(f_go_wrappers, ") ", NULL); +      String *result_wrapper = NULL; +      if (SwigType_type(result) != T_VOID) { +	result_wrapper = goWrapperType(n, result, true); +	Printv(f_go_wrappers, "(swig_result ", result_wrapper, ") ", NULL); +      } +      Printv(f_go_wrappers, "{\n", NULL); + +      if (is_ignored) { +	Printv(f_go_wrappers, "\treturn\n", NULL); +      } else { +	bool result_is_interface = false; +	String *goout = NULL; +	if (SwigType_type(result) != T_VOID) { +	  result_is_interface = goTypeIsInterface(NULL, result); +	  Printv(f_go_wrappers, "\tvar swig_r ", NULL); +	  if (!result_is_interface) { +	    Printv(f_go_wrappers, goType(n, result), NULL); +	  } else { +	    Printv(f_go_wrappers, result_wrapper, NULL); +	  } +	  Printv(f_go_wrappers, "\n", NULL); +	  goout = goTypemapLookup("godirectorout", n, "swig_r"); +	} + +	String *call = NewString(""); +	Printv(call, "\t", NULL); + +	if (SwigType_type(result) != T_VOID) { +	  Printv(call, "swig_r = ", NULL); +	  if (result_is_interface) { +	    Printv(call, result_wrapper, "(getSwigcptr(", NULL); +	  } +	} +	Printv(call, "swig_p.", go_with_over_name, "(", NULL); + +	String *goincode = NewString(""); + +	p = parms; +	for (int i = 0; i < parm_count; ++i) { +	  p = getParm(p); +	  if (i > 0) { +	    Printv(call, ", ", NULL); +	  } +	  SwigType *pt = Getattr(p, "type"); + +	  String *ln = NewString(""); + +	  // If the Go representation is an interface type class, then +	  // we are receiving a uintptr, and must convert to the +	  // interface. +	  bool is_interface = goTypeIsInterface(p, pt); +	  if (is_interface) { +	    // Passing is_result as true to goWrapperType gives us the +	    // name of the Go type we need to convert to an interface. +	    String *wt = goWrapperType(p, pt, true); +	    Printv(ln, wt, "(", NULL); +	    Delete(wt); +	  } + +	  Printv(ln, Getattr(p, "lname"), NULL); + +	  if (is_interface) { +	    Printv(ln, ")", NULL); +	  } + +	  String *goin = goGetattr(p, "tmap:godirectorin"); +	  if (goin == NULL) { +	    Printv(call, ln, NULL); +	  } else { +	    String *ivar = NewString(""); +	    Printf(ivar, "_swig_i_%d", i); +	    String *itm = goType(p, pt); +	    Printv(f_go_wrappers, "\tvar ", ivar, " ", itm, "\n", NULL); +	    goin = Copy(goin); +	    Replaceall(goin, "$input", ln); +	    Replaceall(goin, "$result", ivar); +	    Printv(goincode, goin, "\n", NULL); +	    Delete(goin); +	    Printv(call, ivar, NULL); +	    Delete(ivar); +	  } + +	  Delete(ln); + +	  p = nextParm(p); +	} + +	Printv(call, ")", NULL); + +	if (result_is_interface) { +	  Printv(call, "))", NULL); +	} +	Printv(call, "\n", NULL); + +	Printv(f_go_wrappers, "\tswig_p := swigDirectorLookup(swig_c).(*", director_struct_name, ")\n", NULL); +	Printv(f_go_wrappers, goincode, NULL); +	Printv(f_go_wrappers, call, NULL); +	Delete(call); + +	if (SwigType_type(result) != T_VOID) { +	  if (goout == NULL) { +	    Printv(f_go_wrappers, "\treturn swig_r\n", NULL); +	  } else { +	    String *tm = goImType(n, result); +	    Printv(f_go_wrappers, "\tvar swig_r_1 ", tm, "\n", NULL); +	    Replaceall(goout, "$input", "swig_r"); +	    Replaceall(goout, "$result", "swig_r_1"); +	    Printv(f_go_wrappers, goout, "\n", NULL); +	    Printv(f_go_wrappers, "\treturn swig_r_1\n", NULL); +	  } +	} +      } + +      Printv(f_go_wrappers, "}\n\n", NULL); + +      Delete(result_wrapper); + +      Delete(upcall_wname); +      Delete(upcall_gc_name); +      Delete(go_with_over_name); +    } + +    if (!is_ignored || is_pure_virtual) { +      // Declare the method for the director class. + +      SwigType *rtype = Getattr(n, "conversion_operator") ? 0 : Getattr(n, "classDirectorMethods:type"); +      String *decl = Swig_method_decl(rtype, Getattr(n, "decl"), Getattr(n, "name"), parms, 0); +      Printv(f_c_directors_h, "  virtual ", decl, NULL); +      Delete(decl); + +      String *qname = NewString(""); +      Printv(qname, "SwigDirector_", class_name, "::", Getattr(n, "name"), NULL); +      decl = Swig_method_decl(rtype, Getattr(n, "decl"), qname, parms, 0); +      Printv(w->def, decl, NULL); +      Delete(decl); +      Delete(qname); + +      String *throws = buildThrow(n); +      if (throws) { +	Printv(f_c_directors_h, " ", throws, NULL); +	Printv(w->def, " ", throws, NULL); +	Delete(throws); +      } + +      Printv(f_c_directors_h, ";\n", NULL); + +      Printv(w->def, " {\n", NULL); + +      if (SwigType_type(result) != T_VOID) { +	if (!SwigType_isclass(result)) { +	  if (!(SwigType_ispointer(result) || SwigType_isreference(result))) { +	    String *construct_result = NewStringf("= SwigValueInit< %s >()", SwigType_lstr(result, 0)); +	    Wrapper_add_localv(w, "c_result", SwigType_lstr(result, "c_result"), construct_result, NIL); +	    Delete(construct_result); +	  } else { +	    Wrapper_add_localv(w, "c_result", SwigType_lstr(result, "c_result"), "= 0", NIL); +	  } +	} else { +	  String *cres = SwigType_lstr(result, "c_result"); +	  Printf(w->code, "%s;\n", cres); +	  Delete(cres); +	} +      } + +      if (!is_ignored) { +	makeDirectorMethodWrapper(n, w, callback_name); +      } else { +	assert(is_pure_virtual); +	Printv(w->code, "  _swig_gopanic(\"call to pure virtual function ", Getattr(parent, "sym:name"), name, "\");\n", NULL); +	if (SwigType_type(result) != T_VOID) { +	  String *retstr = SwigType_rcaststr(result, "c_result"); +	  Printv(w->code, "  return ", retstr, ";\n", NULL); +	  Delete(retstr); +	} +      } + +      Printv(w->code, "}", NULL); + +      Replaceall(w->code, "$symname", symname); +      Wrapper_print(w, f_c_directors); +    } + +    Delete(cn); +    Delete(go_type_name); +    Delete(director_struct_name); +    Delete(interface_name); +    Delete(callback_name); +    Delete(upcall_name); +    Delete(go_name); +    DelWrapper(w); + +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * makeDirectorMethodWrapper +   * +   * Emit the function wrapper for a director method. +   * ------------------------------------------------------------ */ +  void makeDirectorMethodWrapper(Node *n, Wrapper *w, String *callback_name) { +    ParmList *parms = Getattr(n, "wrap:parms"); +    SwigType *result = Getattr(n, "type"); + +    Printv(f_c_directors, "extern \"C\" ", NULL); + +    String *fnname = Copy(callback_name); +    Append(fnname, "(int"); + +    Parm *p = parms; +    while (p) { +      while (checkAttribute(p, "tmap:directorin:numinputs", "0")) { +	p = Getattr(p, "tmap:directorin:next"); +      } +      String *cg = gcCTypeForGoValue(p, Getattr(p, "type"), Getattr(p, "lname")); +      Printv(fnname, ", ", cg, NULL); +      Delete(cg); +      p = Getattr(p, "tmap:directorin:next"); +    } + +    Printv(fnname, ")", NULL); + +    if (SwigType_type(result) == T_VOID) { +      Printv(f_c_directors, "void ", fnname, NULL); +    } else { +      String *tm = gcCTypeForGoValue(n, result, fnname); +      Printv(f_c_directors, tm, NULL); +      Delete(tm); +    } + +    Delete(fnname); + +    Printv(f_c_directors, ";\n", NULL); + +    if (SwigType_type(result) != T_VOID) { +      String *r = NewString(Swig_cresult_name()); +      String *tm = gcCTypeForGoValue(n, result, r); +      Wrapper_add_local(w, r, tm); +      Delete(tm); +      Delete(r); +    } + +    String *args = NewString(""); + +    p = parms; +    while (p) { +      while (checkAttribute(p, "tmap:directorin:numinputs", "0")) { +	p = Getattr(p, "tmap:directorin:next"); +      } + +      String *pn = NewString("swig_"); +      Append(pn, Getattr(p, "lname")); +      Setattr(p, "emit:directorinput", pn); + +      String *tm = gcCTypeForGoValue(p, Getattr(p, "type"), pn); +      Wrapper_add_local(w, pn, tm); +      Delete(tm); + +      tm = Getattr(p, "tmap:directorin"); +      if (!tm) { +	Swig_warning(WARN_TYPEMAP_DIRECTORIN_UNDEF, input_file, +		     line_number, "Unable to use type %s as director method argument\n", SwigType_str(Getattr(p, "type"), 0)); +      } else { +	tm = Copy(tm); +	Replaceall(tm, "$input", pn); +	Replaceall(tm, "$owner", 0); +	Printv(w->code, "  ", tm, "\n", NULL); +	Delete(tm); + +	Printv(args, ", ", pn, NULL); +      } + +      p = Getattr(p, "tmap:directorin:next"); +    } + +    Printv(w->code, "  ", NULL); +    if (SwigType_type(result) != T_VOID) { +      Printv(w->code, Swig_cresult_name(), " = ", NULL); +    } +    Printv(w->code, callback_name, "(go_val", args, ");\n", NULL); + +    /* Marshal outputs */ +    for (p = parms; p; ) { +      String *tm; +      if ((tm = Getattr(p, "tmap:directorargout"))) { +	tm = Copy(tm); +	Replaceall(tm, "$result", "jresult"); +	Replaceall(tm, "$input", Getattr(p, "emit:directorinput")); +	Printv(w->code, tm, "\n", NULL); +	Delete(tm); +	p = Getattr(p, "tmap:directorargout:next"); +      } else { +	p = nextSibling(p); +      } +    } + +    if (SwigType_type(result) != T_VOID) { +      String *result_str = NewString("c_result"); +      String *tm = Swig_typemap_lookup("directorout", n, result_str, NULL); +      if (!tm) { +	Swig_warning(WARN_TYPEMAP_DIRECTOROUT_UNDEF, input_file, line_number, +		     "Unable to use type %s as director method result\n", SwigType_str(result, 0)); +      } else { +	tm = Copy(tm); +	Replaceall(tm, "$input", Swig_cresult_name()); +	Replaceall(tm, "$result", "c_result"); +	Printv(w->code, "  ", tm, "\n", NULL); +	String *retstr = SwigType_rcaststr(result, "c_result"); +	Printv(w->code, "  return ", retstr, ";\n", NULL); +	Delete(retstr); +	Delete(tm); +      } +      Delete(result_str); +    } +  } + + +  /* ------------------------------------------------------------ +   * classDirectorEnd +   * +   * Complete support for a director class. +   * ------------------------------------------------------------ */ + +  int classDirectorEnd(Node *n) { +    (void) n; + +    Printv(f_c_directors_h, " private:\n", NULL); +    Printv(f_c_directors_h, "  intgo go_val;\n", NULL); +    Printv(f_c_directors_h, "  Swig_memory *swig_mem;\n", NULL); +    Printv(f_c_directors_h, "};\n\n", NULL); + +    class_name = NULL; +    class_node = NULL; + +    Delete(class_receiver); +    class_receiver = NULL; + +    Delete(class_methods); +    class_methods = NULL; + +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * classDirectorDisown +   * +   * I think Go does not require a disown method. +   * ------------------------------------------------------------ */ + +  int classDirectorDisown(Node *n) { +    (void) n; +    return SWIG_OK; +  } + +  /*---------------------------------------------------------------------- +   * buildThrow() +   * +   * Build and return a throw clause if needed. +   *--------------------------------------------------------------------*/ + +  String *buildThrow(Node *n) { +    if (Getattr(n, "noexcept")) +      return NewString("noexcept"); +    ParmList *throw_parm_list = Getattr(n, "throws"); +    if (!throw_parm_list && !Getattr(n, "throw")) +      return NULL; +    String *ret = NewString("throw("); +    if (throw_parm_list) { +      Swig_typemap_attach_parms("throws", throw_parm_list, NULL); +    } +    bool first = true; +    for (Parm *p = throw_parm_list; p; p = nextSibling(p)) { +      if (Getattr(p, "tmap:throws")) { +	if (first) { +	  first = false; +	} else { +	  Printv(ret, ", ", NULL); +	} +	String *s = SwigType_str(Getattr(p, "type"), 0); +	Printv(ret, s, NULL); +	Delete(s); +      } +    } +    Printv(ret, ")", NULL); +    return ret; +  } + +  /*---------------------------------------------------------------------- +   * extraDirectorProtectedCPPMethodsRequired() +   * +   * We don't need to check upcall when calling methods. +   *--------------------------------------------------------------------*/ + +  bool extraDirectorProtectedCPPMethodsRequired() const { +    return false; +  } + +  /*---------------------------------------------------------------------- +   * makeDispatchFunction +   * +   * Make a dispatch function for an overloaded C++ function.  The +   * receiver parameter is the receiver for a method, unless is_upcall +   * is true.  If is_upcall is true, then the receiver parameter is +   * the type of the first argument to the function. +   *--------------------------------------------------------------------*/ + +  int makeDispatchFunction(Node *n, String *go_name, String *receiver, bool is_static, SwigType *director_struct, bool is_upcall) { +    bool is_director = director_struct ? true : false; + +    String *nodetype = Getattr(n, "nodeType"); +    bool is_constructor = Cmp(nodetype, "constructor") == 0; +    bool is_destructor = Cmp(nodetype, "destructor") == 0; + +    bool can_use_receiver = (!is_constructor && !is_destructor && !is_upcall); + +    bool use_receiver = (!is_static && can_use_receiver); + +    bool add_to_interface = (interfaces && !is_constructor && !is_destructor && !is_static && !is_upcall); + +    List *dispatch = Swig_overload_rank(n, false); +    int nfunc = Len(dispatch); + +    SwigType *all_result; +    bool mismatch; +    if (is_constructor) { +      assert(!is_upcall); +      if (!is_director) { +	all_result = Copy(Getattr(class_node, "classtypeobj")); +      } else { +	all_result = Copy(director_struct); +      } +      mismatch = false; +    } else { +      all_result = NULL; +      mismatch = false; +      bool any_void = false; +      for (int i = 0; i < nfunc; ++i) { +	Node *nn = Getitem(dispatch, i); +	Node *ni = Getattr(nn, "directorNode") ? Getattr(nn, "directorNode") : nn; +	SwigType *result = Getattr(ni, "go:type"); +	assert(result); + +	if (SwigType_type(result) == T_VOID) { +	  if (all_result) { +	    mismatch = true; +	  } +	  any_void = true; +	} else { +	  if (any_void) { +	    mismatch = true; +	  } else if (!all_result) { +	    all_result = Copy(result); +	  } else if (Cmp(result, all_result) != 0) { +	    mismatch = true; +	  } +	} +      } +      if (mismatch) { +	Delete(all_result); +	all_result = NULL; +      } else if (all_result) { +	; +      } else { +	all_result = NewString("void"); +      } +    } + +    Printv(f_go_wrappers, "func ", NULL); + +    if (receiver && use_receiver) { +      Printv(f_go_wrappers, "(p ", receiver, ") ", NULL); +    } + +    Printv(f_go_wrappers, go_name, "(", NULL); +    if (is_director && is_constructor) { +      Printv(f_go_wrappers, "abi interface{}, ", NULL); +      assert(!add_to_interface); +    } +    if (is_upcall) { +      Printv(f_go_wrappers, "p *", receiver, ", ", NULL); +      assert(!add_to_interface); +    } +    Printv(f_go_wrappers, "a ...interface{})", NULL); + +    if (add_to_interface) { +      Printv(interfaces, "\t", go_name, "(a ...interface{})", NULL); +    } + +    if (mismatch) { +      Printv(f_go_wrappers, " interface{}", NULL); +      if (add_to_interface) { +	Printv(interfaces, " interface{}", NULL); +      } +    } else if (all_result && SwigType_type(all_result) != T_VOID) { +      if (is_director && is_constructor) { +	Printv(f_go_wrappers, " ", receiver, NULL); +	if (add_to_interface) { +	  Printv(interfaces, " ", receiver, NULL); +	} +      } else { +	String *tm = goType(n, all_result); +	Printv(f_go_wrappers, " ", tm, NULL); +	if (add_to_interface) { +	  Printv(interfaces, " ", tm, NULL); +	} +	Delete(tm); +      } +    } +    Printv(f_go_wrappers, " {\n", NULL); +    if (add_to_interface) { +      Printv(interfaces, "\n", NULL); +    } + +    Printv(f_go_wrappers, "\targc := len(a)\n", NULL); + +    for (int i = 0; i < nfunc; ++i) { +      int fn = 0; +      Node *nn = Getitem(dispatch, i); +      Node *ni = Getattr(nn, "directorNode") ? Getattr(nn, "directorNode") : nn; +      Parm *pi = Getattr(ni, "wrap:parms"); + +      // If we are using a receiver, we want to ignore a leading self +      // parameter.  Because of the way this is called, there may or +      // may not be a self parameter at this point. +      if (use_receiver && pi && Getattr(pi, "self")) { +	pi = getParm(pi); +	if (pi) { +	  pi = nextParm(pi); +	} +      } + +      int num_required = emit_num_required(pi); +      int num_arguments = emit_num_arguments(pi); +      bool varargs = emit_isvarargs(pi) ? true : false; + +      if (varargs) { +	Printf(f_go_wrappers, "\tif argc >= %d {\n", num_required); +      } else { +	if (num_required == num_arguments) { +	  Printf(f_go_wrappers, "\tif argc == %d {\n", num_required); +	} else { +	  Printf(f_go_wrappers, "\tif argc >= %d && argc <= %d {\n", num_required, num_arguments); +	} +      } + +      // Build list of collisions with the same number of arguments. +      List *coll = NewList(); +      for (int k = i + 1; k < nfunc; ++k) { +	Node *nnk = Getitem(dispatch, k); +	Node *nk = Getattr(nnk, "directorNode") ? Getattr(nnk, "directorNode") : nnk; +	Parm *pk = Getattr(nk, "wrap:parms"); +	if (use_receiver && pk && Getattr(pk, "self")) { +	  pk = getParm(pk); +	  if (pk) { +	    pk = nextParm(pk); +	  } +	} +	int nrk = emit_num_required(pk); +	int nak = emit_num_arguments(pk); +	if ((nrk >= num_required && nrk <= num_arguments) +	    || (nak >= num_required && nak <= num_arguments) +	    || (nrk <= num_required && nak >= num_arguments) +	    || (varargs && nrk >= num_required)) { +	  Append(coll, nk); +	} +      } + +      int num_braces = 0; +      if (Len(coll) > 0 && num_arguments > 0) { +	int j = 0; +	Parm *pj = pi; +	while (pj) { +	  pj = getParm(pj); +	  if (!pj) { +	    break; +	  } + +	  // If all the overloads have the same type in this position, +	  // we can omit the check. +	  SwigType *tm = goOverloadType(pj, Getattr(pj, "type")); +	  bool emitcheck = false; +	  for (int k = 0; k < Len(coll) && !emitcheck; ++k) { +	    Node *nk = Getitem(coll, k); +	    Parm *pk = Getattr(nk, "wrap:parms"); +	    if (use_receiver && pk && Getattr(pk, "self")) { +	      pk = getParm(pk); +	      if (pk) { +		pk = nextParm(pk); +	      } +	    } +	    int nak = emit_num_arguments(pk); +	    if (nak <= j) +	      continue; +	    int l = 0; +	    Parm *pl = pk; +	    while (pl && l <= j) { +	      pl = getParm(pl); +	      if (!pl) { +		break; +	      } +	      if (l == j) { +		SwigType *tml = goOverloadType(pl, Getattr(pl, "type")); +		if (Cmp(tm, tml) != 0) { +		  emitcheck = true; +		} +		Delete(tml); +	      } +	      pl = nextParm(pl); +	      ++l; +	    } +	  } + +	  if (emitcheck) { +	    if (j >= num_required) { +	      Printf(f_go_wrappers, "\t\tif argc > %d {\n", j); +	      ++num_braces; +	    } + +	    fn = i + 1; +	    Printf(f_go_wrappers, "\t\tif _, ok := a[%d].(%s); !ok {\n", j, tm); +	    Printf(f_go_wrappers, "\t\t\tgoto check_%d\n", fn); +	    Printv(f_go_wrappers, "\t\t}\n", NULL); +	  } + +	  Delete(tm); + +	  pj = nextParm(pj); + +	  ++j; +	} +      } + +      for (; num_braces > 0; --num_braces) { +	Printv(f_go_wrappers, "\t\t}\n", NULL); +      } + +      // We may need to generate multiple calls if there are variable +      // argument lists involved.  Build the start of the call. + +      String *start = NewString(""); + +      SwigType *result = Getattr(ni, "go:type"); + +      if (is_constructor) { +	result = all_result; +      } else if (is_destructor) { +	result = NULL; +      } + +      if (result && SwigType_type(result) != T_VOID && (!all_result || SwigType_type(all_result) != T_VOID)) { +	Printv(start, "return ", NULL); +      } + +      bool advance_parm = false; + +      if (receiver && use_receiver) { +	Printv(start, "p.", go_name, NULL); +      } else if (can_use_receiver && !isStatic(ni) && pi && Getattr(pi, "self")) { +	// This is an overload of a static function and a non-static +	// function. +	assert(num_required > 0); +	SwigType *tm = goWrapperType(pi, Getattr(pi, "type"), true); +	String *nm = buildGoName(Getattr(ni, "sym:name"), false, isFriend(ni)); +	Printv(start, "a[0].(", tm, ").", nm, NULL); +	Delete(nm); +	Delete(tm); +	advance_parm = true; +      } else { +	Printv(start, go_name, NULL); +      } + +      Printv(start, Getattr(ni, "sym:overname"), "(", NULL); + +      bool need_comma = false; + +      if (is_director && is_constructor) { +	Printv(start, "abi", NULL); +	need_comma = true; +      } +      if (is_upcall) { +	Printv(start, "p", NULL); +	need_comma = true; +      } +      Parm *p = pi; +      int pn = 0; +      if (advance_parm) { +	p = getParm(p); +	if (p) { +	  p = nextParm(p); +	} +	++pn; +      } +      while (pn < num_required) { +	p = getParm(p); + +	if (need_comma) { +	  Printv(start, ", ", NULL); +	} + +	SwigType *tm = goType(p, Getattr(p, "type")); +	Printf(start, "a[%d].(%s)", pn, tm); +	Delete(tm); + +	need_comma = true; +	++pn; +	p = nextParm(p); +      } + +      String *end = NULL; +      if (!result || SwigType_type(result) == T_VOID || (all_result && SwigType_type(all_result) == T_VOID)) { +	end = NewString(""); +	Printv(end, "return", NULL); +	if (!all_result || SwigType_type(all_result) != T_VOID) { +	  Printv(end, " 0", NULL); +	} +      } + +      if (num_required == num_arguments) { +	Printv(f_go_wrappers, "\t\t", start, ")\n", NULL); +	if (end) { +	  Printv(f_go_wrappers, "\t\t", end, "\n", NULL); +	} +      } else { +	Printv(f_go_wrappers, "\t\tswitch argc {\n", NULL); +	for (int j = num_required; j <= num_arguments; ++j) { +	  Printf(f_go_wrappers, "\t\tcase %d:\n", j); +	  Printv(f_go_wrappers, "\t\t\t", start, NULL); +	  bool nc = need_comma; +	  for (int k = num_required; k < j; ++k) { +	    if (nc) { +	      Printv(f_go_wrappers, ", ", NULL); +	    } +	    Printf(f_go_wrappers, "a[%d]", k); +	    nc = true; +	  } +	  Printv(f_go_wrappers, ")\n", NULL); +	  if (end) { +	    Printv(f_go_wrappers, "\t\t\t", end, "\n", NULL); +	  } +	} +	Printv(f_go_wrappers, "\t\t}\n", NULL); +      } + +      Printv(f_go_wrappers, "\t}\n", NULL); + +      if (fn != 0) { +	Printf(f_go_wrappers, "check_%d:\n", fn); +      } + +      Delete(coll); +    } + +    Printv(f_go_wrappers, "\tpanic(\"No match for overloaded function call\")\n", NULL); +    Printv(f_go_wrappers, "}\n\n", NULL); + +    Delete(all_result); +    Delete(dispatch); + +    return SWIG_OK; +  } + +  /* ---------------------------------------------------------------------- +   * checkFunctionVisibility() +   * +   * Return true if we should write out a function based on its +   * visibility, false otherwise. +   * ---------------------------------------------------------------------- */ + +  bool checkFunctionVisibility(Node *n, Node *parent) { +    // Write out a public function. +    if (is_public(n)) +      return true; +    // Don't write out a private function. +    if (is_private(n)) +      return false; +    // Write a protected function for a director class in +    // dirprot_mode. +    if (parent == NULL) { +      return false; +    } +    if (dirprot_mode() && Swig_directorclass(parent)) +      return true; +    // Otherwise don't write out a protected function. +    return false; +  } + + +  /* ---------------------------------------------------------------------- +   * exportedName() +   * +   * Given a C/C++ name, return a name in Go which will be exported. +   * If the first character is an upper case letter, this returns a +   * copy of its argument.  If the first character is a lower case +   * letter, this forces it to upper case.  Otherwise, this prepends +   * 'X'. +   * ---------------------------------------------------------------------- */ + +  String *exportedName(String *name) { +    String *copy = Copy(name); +    char c = *Char(copy); +    if (islower(c)) { +      char l[2]; +      char u[2]; +      l[0] = c; +      l[1] = '\0'; +      u[0] = toupper(c); +      u[1] = '\0'; +      Replace(copy, l, u, DOH_REPLACE_FIRST); +    } else if (!isalpha(c)) { +      char l[2]; +      char u[3]; +      l[0] = c; +      l[1] = '\0'; +      u[0] = 'X'; +      u[1] = c; +      u[2] = '\0'; +      Replace(copy, l, u, DOH_REPLACE_FIRST); +    } +    String *ret = Swig_name_mangle(copy); +    Delete(copy); +    return ret; +  } + +  /* ---------------------------------------------------------------------- +   * removeClassname() +   * +   * If the name starts with the current class name, followed by an +   * underscore, remove it.  If there is no current class name, this +   * simply returns a copy of the name.  This undoes Swig's way of +   * recording the class name in a member name. +   * ---------------------------------------------------------------------- */ + +  String *removeClassname(String *name) { +    String *copy = Copy(name); +    if (class_name) { +      char *p = Char(name); +      if (Strncmp(name, class_name, Len(class_name)) == 0 && p[Len(class_name)] == '_') { +	Replace(copy, class_name, "", DOH_REPLACE_FIRST); +	Replace(copy, "_", "", DOH_REPLACE_FIRST); +      } +    } +    return copy; +  } + +  /* ---------------------------------------------------------------------- +   * buildGoName() +   * +   * Build the name to use for an ordinary function, variable, or +   * whatever in Go.  The name argument is something like the sym:name +   * attribute of the node.  If is_static is false, this could be a +   * method, and the returned name will be the name of the +   * method--i.e., it will not include the class name. +   * ---------------------------------------------------------------------- */ + +  String *buildGoName(String *name, bool is_static, bool is_friend) { +    String *nw = NewString(""); +    if (is_static && !is_friend && class_name) { +      String *c1 = exportedName(class_name); +      Append(nw, c1); +      Delete(c1); +    } +    String *c2 = removeClassname(name); +    String *c3 = exportedName(c2); +    Append(nw, c3); +    Delete(c2); +    Delete(c3); +    String *ret = Swig_name_mangle(nw); +    Delete(nw); +    return ret; +  } + +  /* ---------------------------------------------------------------------- +   * buildGoWrapperName() +   * +   * Build the name to use for a Go wrapper function.  This is a +   * function called by the real Go function in order to convert C++ +   * classes from interfaces to pointers, and other such conversions +   * between the Go type and the C++ type. +   * ---------------------------------------------------------------------- */ + +  String *buildGoWrapperName(String *name, String *overname) { +    String *s1 = NewString("_swig_wrap_"); +    Append(s1, name); +    String *s2 = Swig_name_mangle(s1); +    Delete(s1); +    if (overname) { +      Append(s2, overname); +    } +    return s2; +  } + +  /* ---------------------------------------------------------------------- +   * checkNameConflict() +   * +   * Check for a name conflict on the name we are going to use in Go. +   * These conflicts are likely because of the enforced +   * capitalization.  When we find one, issue a warning and return +   * false.  If the name is OK, return true. +   * ---------------------------------------------------------------------- */ + +  bool checkNameConflict(String* name, Node* n, const_String_or_char_ptr scope) { +    Node *lk = symbolLookup(name, scope); +    if (lk) { +      String *n1 = Getattr(n, "sym:name"); +      if (!n1) { +	n1 = Getattr(n, "name"); +      } +      String *n2 = Getattr(lk, "sym:name"); +      if (!n2) { +	n2 = Getattr(lk, "name"); +      } +      Swig_warning(WARN_GO_NAME_CONFLICT, input_file, line_number, +		   "Ignoring '%s' due to Go name ('%s') conflict with '%s'\n", +		   n1, name, n2); +      return false; +    } +    bool r = addSymbol(name, n, scope) ? true : false; +    assert(r); +    (void)r; +    return true; +  } + +  /* ---------------------------------------------------------------------- +   * checkIgnoredParameters() +   * +   * If any of the parameters of this function, or the return type, +   * are ignored due to a name conflict, give a warning and return +   * false. +   * ---------------------------------------------------------------------- */ + +  bool checkIgnoredParameters(Node *n, String *go_name) { +    ParmList *parms = Getattr(n, "parms"); +    if (parms) { +      Wrapper *dummy = NewWrapper(); +      emit_attach_parmmaps(parms, dummy); +      int parm_count = emit_num_arguments(parms); +      Parm *p = parms; + +      for (int i = 0; i < parm_count; ++i) { +	p = getParm(p); +	if (!checkIgnoredType(n, go_name, Getattr(p, "type"))) { +	  DelWrapper(dummy); +	  return false; +	} +	p = nextParm(p); +      } + +      DelWrapper(dummy); +    } + +    if (!checkIgnoredType(n, go_name, Getattr(n, "type"))) { +      return false; +    } + +    return true; +  } + +  /* ---------------------------------------------------------------------- +   * checkIgnoredType() +   * +   * If this type is being ignored due to a name conflict, give a +   * warning and return false. +   * ---------------------------------------------------------------------- */ + +  bool checkIgnoredType(Node *n, String *go_name, SwigType *type) { +    if (hasGoTypemap(n, type)) { +      return true; +    } + +    SwigType *t = SwigType_typedef_resolve_all(type); + +    bool ret = true; +    bool is_conflict = false; +    Node *e = Language::enumLookup(t); +    if (e) { +      if (GetFlag(e, "go:conflict")) { +	is_conflict = true; +      } +    } else if (SwigType_issimple(t)) { +      Node *cn = classLookup(t); +      if (cn) { +	if (GetFlag(cn, "go:conflict")) { +	  is_conflict = true; +	} +      } +    } else if (SwigType_ispointer(t) || SwigType_isarray(t) || SwigType_isqualifier(t) || SwigType_isreference(t)) { +      SwigType *r = Copy(t); +      if (SwigType_ispointer(r)) { +	SwigType_del_pointer(r); +      } else if (SwigType_isarray(r)) { +	SwigType_del_array(r); +      } else if (SwigType_isqualifier(r)) { +	SwigType_del_qualifier(r); +      } else { +	SwigType_del_reference(r); +      } + +      if (!checkIgnoredType(n, go_name, r)) { +	ret = false; +      } + +      Delete(r); +    } + +    if (is_conflict) { +      String *s = SwigType_str(t, NULL); +      Swig_warning(WARN_GO_NAME_CONFLICT, input_file, line_number, +		   "Ignoring '%s' (Go name '%s') due to Go name conflict for parameter or result type '%s'\n", +		   Getattr(n, "name"), go_name, s); +      Delete(s); +      ret = false; +    } + +    Delete(t); + +    return ret; +  } + +  /* ---------------------------------------------------------------------- +   * goType() +   * +   * Given a SWIG type, return a string for the type in Go. +   * ---------------------------------------------------------------------- */ + +  String *goType(Node *n, SwigType *type) { +    return goTypeWithInfo(n, type, false, NULL); +  } + +  /* ---------------------------------------------------------------------- +   * goImType() +   * +   * Given a SWIG type, return a string for the intermediate Go type +   * to pass to C/C++.  This is like goType except that it looks for +   * an imtype typemap entry first. +   * ---------------------------------------------------------------------- */ + +  String *goImType(Node *n, SwigType *type) { +    return goTypeWithInfo(n, type, true, NULL); +  } + +  /* ---------------------------------------------------------------------- +   * goTypeWithInfo() +   * +   * Like goType, but return some more information. +   * +   * If use_imtype is true, this look for a imtype typemap entry. +   * +   * If the p_is_interface parameter is not NULL, this sets +   * *p_is_interface to indicate whether this type is going to be +   * represented by a Go interface type.  These are cases where the Go +   * code needs to make some adjustments when passing values back and +   * forth with C/C++. +   * ---------------------------------------------------------------------- */ + +  String *goTypeWithInfo(Node *n, SwigType *type, bool use_imtype, bool *p_is_interface) { +    if (p_is_interface) { +      *p_is_interface = false; +    } + +    String *ret = NULL; +    if (use_imtype) { +      if (n && Cmp(type, Getattr(n, "type")) == 0) { +	if (Strcmp(Getattr(n, "nodeType"), "parm") == 0) { +	  ret = Getattr(n, "tmap:imtype"); +	} +	if (!ret) { +	  ret = Swig_typemap_lookup("imtype", n, "", NULL); +	} +      } else { +	Parm *p = NewParm(type, "goImType", n); +	ret = Swig_typemap_lookup("imtype", p, "", NULL); +	Delete(p); +      } +    } +    if (!ret) { +      if (n && Cmp(type, Getattr(n, "type")) == 0) { +	if (Strcmp(Getattr(n, "nodeType"), "parm") == 0) { +	  ret = Getattr(n, "tmap:gotype"); +	} +	if (!ret) { +	  ret = Swig_typemap_lookup("gotype", n, "", NULL); +	} +      } else { +	Parm *p = NewParm(type, "goType", n); +	ret = Swig_typemap_lookup("gotype", p, "", NULL); +	Delete(p); +      } +    } + +    if (ret && Strstr(ret, "$gotypename") != 0) { +      ret = NULL; +    } + +    if (ret) { +      return Copy(ret); +    } + +    SwigType *t = SwigType_typedef_resolve_all(type); + +    if (SwigType_isenum(t)) { +      Node *e = Language::enumLookup(t); +      if (e) { +	ret = goEnumName(e); +      } else if (Strcmp(t, "enum ") == 0) { +	ret = NewString("int"); +      } else { +	// An unknown enum - one that has not been parsed (neither a C enum forward reference nor a definition) or an ignored enum +	String *tt = Copy(t); +	Replace(tt, "enum ", "", DOH_REPLACE_ANY); +	ret = exportedName(tt); +	Setattr(undefined_enum_types, t, ret); +	Delete(tt); +      } +    } else if (SwigType_isfunctionpointer(t) || SwigType_isfunction(t)) { +      ret = NewString("_swig_fnptr"); +    } else if (SwigType_ismemberpointer(t)) { +      ret = NewString("_swig_memberptr"); +    } else if (SwigType_issimple(t)) { +      Node *cn = classLookup(t); +      if (cn) { +	ret = Getattr(cn, "sym:name"); +	if (!ret) { +	  ret = Getattr(cn, "name"); +	} +	ret = exportedName(ret); + +	Node *cnmod = Getattr(cn, "module"); +	if (!cnmod || Strcmp(Getattr(cnmod, "name"), module) == 0) { +	  Setattr(undefined_types, t, t); +	} else { +	  String *nw = NewString(""); +	  Printv(nw, getModuleName(Getattr(cnmod, "name")), ".", ret, NULL); +	  Delete(ret); +	  ret = nw; +	} +      } else { +	// SWIG does not know about this type. +	ret = exportedName(t); +	Setattr(undefined_types, t, t); +      } +      if (p_is_interface) { +	*p_is_interface = true; +      } +    } else if (SwigType_ispointer(t) || SwigType_isarray(t)) { +      SwigType *r = Copy(t); +      if (SwigType_ispointer(r)) { +	SwigType_del_pointer(r); +      } else { +	SwigType_del_array(r); +      } + +      if (SwigType_type(r) == T_VOID) { +	ret = NewString("uintptr"); +      } else { +	bool is_interface; +	String *base = goTypeWithInfo(n, r, false, &is_interface); + +	// At the Go level, an unknown or class type is handled as an +	// interface wrapping a pointer.  This means that if a +	// function returns the C type X, we will be wrapping the C +	// type X*.  In Go we will call that type X.  That means that +	// if a C function expects X*, we can pass the Go type X.  And +	// that means that when we see the C type X*, we should use +	// the Go type X. + +	// The is_interface variable tells us this.  However, it will +	// be true both for the case of X and for the case of X*.  If +	// r is a pointer here, then we are looking at X**.  There is +	// really no good way for us to handle that. +	bool is_pointer_to_pointer = false; +	if (is_interface) { +	  SwigType *c = Copy(r); +	  if (SwigType_isqualifier(c)) { +	    SwigType_del_qualifier(c); +	    if (SwigType_ispointer(c) || SwigType_isarray(c)) { +	      is_pointer_to_pointer = true; +	    } +	  } +	  Delete(c); +	} + +	if (is_interface) { +	  if (!is_pointer_to_pointer) { +	    ret = base; +	    if (p_is_interface) { +	      *p_is_interface = true; +	    } +	  } else { +	    ret = NewString("uintptr"); +	  } +	} else { +	  ret = NewString("*"); +	  Append(ret, base); +	  Delete(base); +	} +      } + +      Delete(r); +    } else if (SwigType_isreference(t)) { +      SwigType *r = Copy(t); +      SwigType_del_reference(r); + +      // If this is a const reference, and we are looking at a pointer +      // to it, then we just use the pointer we already have. +      bool add_pointer = true; +      if (SwigType_isqualifier(r)) { +	String *q = SwigType_parm(r); +	if (Strcmp(q, "const") == 0) { +	  SwigType *c = Copy(r); +	  SwigType_del_qualifier(c); +	  if (SwigType_ispointer(c)) { +	    add_pointer = false; +	  } +	  Delete(c); +	} +      } +      if (add_pointer) { +	SwigType_add_pointer(r); +      } +      ret = goTypeWithInfo(n, r, false, p_is_interface); +      Delete(r); +    } else if (SwigType_isqualifier(t)) { +      SwigType *r = Copy(t); +      SwigType_del_qualifier(r); +      ret = goTypeWithInfo(n, r, false, p_is_interface); +      Delete(r); +    } else if (SwigType_isvarargs(t)) { +      ret = NewString("[]interface{}"); +    } + +    Delete(t); + +    if (!ret) { +      Swig_warning(WARN_LANG_NATIVE_UNIMPL, input_file, line_number, "No Go typemap defined for %s\n", SwigType_str(type, 0)); +      ret = NewString("uintptr"); +    } + +    return ret; +  } + +  /* ---------------------------------------------------------------------- +   * cgoTypeForGoValue() +   * +   * Given a SWIG type, return a string for the C type to use for the +   * cgo wrapper code.  This always returns a simple identifier, since +   * it is used in Go code as C.name. +   * +   * This sets *c_struct_type if the C type uses a struct where the Go +   * type uses a simple type.  This is true for strings and slices. +   * When this is true the Go code has to jump through unsafe hoops to +   * pass the type checker. +   * ---------------------------------------------------------------------- */ + +  String *cgoTypeForGoValue(Node *n, SwigType *type, bool *c_struct_type) { +    *c_struct_type = false; + +    bool is_interface; +    String *go_type = goTypeWithInfo(n, type, true, &is_interface); +    if (is_interface) { +      Delete(go_type); +      return NewString("uintptr_t"); +    } +    if (Strcmp(go_type, "uintptr") == 0) { +      Delete(go_type); +      return NewString("uintptr_t"); +    } +    if (((char*)Char(go_type))[0] == '*') { +      // Treat all pointers as void*.  There is no meaningful type +      // checking going on here anyhow, and that lets us avoid +      // worrying about defining the base type of the pointer. +      Delete(go_type); +      return NewString("swig_voidp"); +    } + +    // Check for some Go types that are really pointers under the covers. +    bool is_hidden_pointer = Strncmp(go_type, "func(", 5) == 0 || Strncmp(go_type, "map[", 4) == 0 || Strncmp(go_type, "chan ", 5) == 0; + +    Delete(go_type); + +    String *ct = Getattr(n, "emit:cgotype"); +    if (ct) { +      *c_struct_type = Getattr(n, "emit:cgotypestruct") ? true : false; +      return Copy(ct); +    } + +    String *t = Copy(type); +    if (SwigType_isarray(t) && Getattr(n, "tmap:gotype") == NULL) { +      SwigType_del_array(t); +      SwigType_add_pointer(t); +    } + +    bool add_typedef = true; + +    static int count; +    ++count; +    ct = NewStringf("swig_type_%d", count); + +    String *gct = gcCTypeForGoValue(n, t, ct); +    Delete(t); + +    if (Strncmp(gct, "_gostring_", 10) == 0 || Strncmp(gct, "_goslice_", 9) == 0) { +      *c_struct_type = true; +      Setattr(n, "emit:cgotypestruct", type); +    } else { +      char *p = Strstr(gct, ct); +      if (p != NULL && p > (char*)Char(gct) && p[-1] == '*' && p[Len(ct)] == '\0') { +	// Treat all pointers as void*.  See above. +	Delete(ct); +	--count; +	ct = NewString("swig_voidp"); +	add_typedef = false; +	if (is_hidden_pointer) { +	  // A Go type that is really a pointer, like func, map, chan, +	  // is being represented in C by a pointer.  This is fine, +	  // but we have to memcpy the type rather than simply +	  // converting it. +	  *c_struct_type = true; +	  Setattr(n, "emit:cgotypestruct", type); +	} +      } + +      if (Strncmp(gct, "bool ", 5) == 0) { +	// Change the C++ type bool to the C type _Bool. +	Replace(gct, "bool", "_Bool", DOH_REPLACE_FIRST); +      } +      if (Strncmp(gct, "intgo ", 6) == 0) { +	// We #define intgo to swig_intgo for the cgo comment. +	Replace(gct, "intgo", "swig_intgo", DOH_REPLACE_FIRST); +      } +      p = Strstr(gct, ct); +      if (p != NULL && p > (char*)Char(gct) && p[-1] == ' ' && p[Len(ct)] == '\0') { +	String *q = NewStringWithSize(gct, Len(gct) - Len(ct) - 1); +	if (validIdentifier(q)) { +	  // This is a simple type name, and we can use it directly. +	  Delete(ct); +	  --count; +	  ct = q; +	  add_typedef = false; +	} +      } +    } +    if (add_typedef) { +      Printv(f_cgo_comment_typedefs, "typedef ", gct, ";\n", NULL); +    } + +    Setattr(n, "emit:cgotype", ct); + +    Delete(gct); + +    return Copy(ct); +  } + +  /* ---------------------------------------------------------------------- +   * goWrapperType() +   * +   * Given a type, return a string for the type to use for the wrapped +   * Go function.  This function exists because for a C++ class we +   * need to convert interface and reference types. +   * ---------------------------------------------------------------------- */ + +  String *goWrapperType(Node *n, SwigType *type, bool is_result) { +    bool is_interface; +    String *ret = goTypeWithInfo(n, type, true, &is_interface); + +    // If this is an interface, we want to pass the real type. +    if (is_interface) { +      Delete(ret); +      if (!is_result) { +	ret = NewString("uintptr"); +      } else { +	SwigType *ty = SwigType_typedef_resolve_all(type); +	while (true) { +	  if (SwigType_ispointer(ty)) { +	    SwigType_del_pointer(ty); +	  } else if (SwigType_isarray(ty)) { +	    SwigType_del_array(ty); +	  } else if (SwigType_isreference(ty)) { +	    SwigType_del_reference(ty); +	  } else if (SwigType_isqualifier(ty)) { +	    SwigType_del_qualifier(ty); +	  } else { +	    break; +	  } +	} +	assert(SwigType_issimple(ty)); +	String *p = goCPointerType(ty, true); +	Delete(ty); +	ret = p; +      } +    } + +    return ret; +  } + +  /* ---------------------------------------------------------------------- +   * goOverloadType() +   * +   * Given a type, return the Go type to use when dispatching of +   * overloaded functions.  This is normally just the usual Go type. +   * However, for a C++ class, the usual Go type is an interface type. +   * And if that interface type represents a C++ type that SWIG does +   * not know about, then the interface type generated for any C++ +   * class will match that interface.  So for that case, we match on +   * the underlying integer type. +   * +   * It has to work this way so that we can handle a derived type of a +   * %ignore'd type.  It's unlikely that anybody will have a value of +   * an undefined type, but we support it because it worked in the +   * past. +   * ---------------------------------------------------------------------- */ + +  String *goOverloadType(Node *n, SwigType *type) { +    SwigType *ty = SwigType_typedef_resolve_all(type); +    while (true) { +      if (SwigType_ispointer(ty)) { +	SwigType_del_pointer(ty); +      } else if (SwigType_isarray(ty)) { +	SwigType_del_array(ty); +      } else if (SwigType_isreference(ty)) { +	SwigType_del_reference(ty); +      } else if (SwigType_isqualifier(ty)) { +	SwigType_del_qualifier(ty); +      } else { +	break; +      } +    } + +    String* go_type = goType(n, ty); + +    if (Getattr(undefined_types, ty) && !Getattr(defined_types, go_type)) { +      Delete(go_type); +      return goWrapperType(n, type, true); +    } + +    Delete(go_type); +    return goType(n, type); +  } + +  /* ---------------------------------------------------------------------- +   * goCPointerType() +   * +   * Return the name of the Go type to use for the C pointer value. +   * The regular C type is the name of an interface type which wraps a +   * pointer whose name is returned by this function. +   * ---------------------------------------------------------------------- */ + +  String *goCPointerType(SwigType *type, bool add_to_hash) { +    SwigType *ty = SwigType_typedef_resolve_all(type); +    Node *cn = classLookup(ty); +    String *ex; +    String *ret; +    if (!cn) { +      if (add_to_hash) { +	Setattr(undefined_types, ty, ty); +      } +      ret = NewString("Swigcptr"); +      ex = exportedName(ty); +      Append(ret, ex); +    } else { +      String *cname = Getattr(cn, "sym:name"); +      if (!cname) { +	cname = Getattr(cn, "name"); +      } +      ex = exportedName(cname); +      Node *cnmod = Getattr(cn, "module"); +      if (!cnmod || Strcmp(Getattr(cnmod, "name"), module) == 0) { +	if (add_to_hash) { +	  Setattr(undefined_types, ty, ty); +	} +	ret = NewString("Swigcptr"); +	Append(ret, ex); +      } else { +	ret = NewString(""); +	Printv(ret, getModuleName(Getattr(cnmod, "name")), ".Swigcptr", ex, NULL); +      } +    } +    Delete(ty); +    Delete(ex); +    return ret; +  } + +  /* ---------------------------------------------------------------------- +   * gcCTypeForGoValue() +   * +   * Given a type, return the C/C++ type which will be used to catch +   * the value in Go.  This is the gc version. +   * ---------------------------------------------------------------------- */ + +  String *gcCTypeForGoValue(Node *n, SwigType *type, String *name) { +    bool is_interface; +    String *gt = goTypeWithInfo(n, type, true, &is_interface); + +    String *tail = NewString(""); +    SwigType *t = SwigType_typedef_resolve_all(type); +    bool is_const_ref = false; +    if (SwigType_isreference(t)) { +      SwigType* tt = Copy(t); +      SwigType_del_reference(tt); +      if (SwigType_isqualifier(tt)) { +	String* q = SwigType_parm(tt); +	if (Strcmp(q, "const") == 0) { +	  is_const_ref = true; +	} +      } +      Delete(tt); +    } +    if (!is_const_ref) { +      while (Strncmp(gt, "*", 1) == 0) { +	Replace(gt, "*", "", DOH_REPLACE_FIRST); +	Printv(tail, "*", NULL); +      } +    } +    Delete(t); + +    bool is_string = Strcmp(gt, "string") == 0; +    bool is_slice = Strncmp(gt, "[]", 2) == 0; +    bool is_function = Strcmp(gt, "_swig_fnptr") == 0; +    bool is_member = Strcmp(gt, "_swig_memberptr") == 0; +    bool is_complex64 = Strcmp(gt, "complex64") == 0; +    bool is_complex128 = Strcmp(gt, "complex128") == 0; +    bool is_bool = false; +    bool is_int8 = false; +    bool is_int16 = false; +    bool is_int = Strcmp(gt, "int") == 0 || Strcmp(gt, "uint") == 0; +    bool is_int32 = false; +    bool is_int64 = false; +    bool is_float32 = false; +    bool is_float64 = false; + +    bool has_typemap = (n != NULL && Getattr(n, "tmap:gotype") != NULL) || hasGoTypemap(n, type); +    if (has_typemap) { +      is_bool = Strcmp(gt, "bool") == 0; +      is_int8 = Strcmp(gt, "int8") == 0 || Strcmp(gt, "uint8") == 0 || Strcmp(gt, "byte") == 0; +      is_int16 = Strcmp(gt, "int16") == 0 || Strcmp(gt, "uint16") == 0; +      is_int32 = Strcmp(gt, "int32") == 0 || Strcmp(gt, "uint32") == 0; +      is_int64 = Strcmp(gt, "int64") == 0 || Strcmp(gt, "uint64") == 0; +      is_float32 = Strcmp(gt, "float32") == 0; +      is_float64 = Strcmp(gt, "float64") == 0; +    } +    Delete(gt); + +    String *ret; +    if (is_string) { +      // Note that we don't turn a reference to a string into a +      // pointer to a string.  Strings are immutable anyhow. +      ret = NewString(""); +      Printv(ret, "_gostring_", tail, " ", name, NULL); +      Delete(tail); +      return ret; +    } else if (is_slice) { +      // Slices are always passed as a _goslice_, whether or not references +      // are involved. +      ret = NewString(""); +      Printv(ret, "_goslice_", tail, " ", name, NULL); +      Delete(tail); +      return ret; +    } else if (is_function || is_member) { +      ret = NewString(""); +      Printv(ret, "void*", tail, " ", name, NULL); +      Delete(tail); +      return ret; +    } else if (is_complex64) { +      ret = NewString("_Complex float "); +    } else if (is_complex128) { +      ret = NewString("_Complex double "); +    } else if (is_interface) { +      SwigType *t = SwigType_typedef_resolve_all(type); +      if (SwigType_ispointer(t)) { +	SwigType_del_pointer(t); +      } +      if (SwigType_isreference(t)) { +	SwigType_del_reference(t); +      } +      SwigType_add_pointer(t); +      ret = SwigType_lstr(t, name); +      Delete(t); +      Delete(tail); +      return ret; +    } else { +      SwigType *t = SwigType_typedef_resolve_all(type); +      if (!has_typemap && SwigType_isreference(t)) { +	// A const reference to a known type, or to a pointer, is not +	// mapped to a pointer. +	SwigType_del_reference(t); +	if (SwigType_isqualifier(t)) { +	  String *q = SwigType_parm(t); +	  if (Strcmp(q, "const") == 0) { +	    SwigType_del_qualifier(t); +	    if (hasGoTypemap(n, t) || SwigType_ispointer(t)) { +	      if (is_int) { +		ret = NewString("intgo "); +		Append(ret, name); +	      } else if (is_int64) { +		ret = NewString("long long "); +		Append(ret, name); +	      } else { +		ret = SwigType_lstr(t, name); +	      } +	      Delete(q); +	      Delete(t); +	      Delete(tail); +	      return ret; +	    } +	  } +	  Delete(q); +	} +      } + +      if (Language::enumLookup(t) != NULL) { +	is_int = true; +      } else { +	SwigType *tstripped = SwigType_strip_qualifiers(t); +	if (SwigType_isenum(tstripped)) +	  is_int = true; +	Delete(tstripped); +      } + +      Delete(t); +      if (is_bool) { +	ret = NewString("bool "); +      } else if (is_int8) { +	ret = NewString("char "); +      } else if (is_int16) { +	ret = NewString("short "); +      } else if (is_int) { +	ret = NewString("intgo "); +      } else if (is_int32) { +	ret = NewString("int "); +      } else if (is_int64) { +	ret = NewString("long long "); +      } else if (is_float32) { +	ret = NewString("float "); +      } else if (is_float64) { +	ret = NewString("double "); +      } else { +	Delete(tail); +	return SwigType_lstr(type, name); +      } +    } + +    Append(ret, tail); +    if (!has_typemap && SwigType_isreference(type)) { +      Append(ret, "* "); +    } +    Append(ret, name); +    Delete(tail); +    return ret; +  } + +  /* ---------------------------------------------------------------------- +   * goTypeIsInterface +   * +   * Return whether this C++ type is represented as an interface type +   * in Go.  These types require adjustments in the Go code when +   * passing them back and forth between Go and C++. +   * ---------------------------------------------------------------------- */ + +  bool goTypeIsInterface(Node *n, SwigType *type) { +    bool is_interface; +    Delete(goTypeWithInfo(n, type, false, &is_interface)); +    return is_interface; +  } + +  /* ---------------------------------------------------------------------- +   * hasGoTypemap +   * +   * Return whether a type has a "gotype" typemap entry. +   * ---------------------------------------------------------------------- */ + +  bool hasGoTypemap(Node *n, SwigType *type) { +    Parm *p = NewParm(type, "test", n); +    SwigType *tm = Swig_typemap_lookup("gotype", p, "", NULL); +    Delete(p); +    if (tm && Strstr(tm, "$gotypename") == 0) { +      Delete(tm); +      return true; +    } +    Delete(tm); +    return false; +  } + +  /* ---------------------------------------------------------------------- +   * goEnumName() +   * +   * Given an enum node, return a string to use for the enum type in Go. +   * ---------------------------------------------------------------------- */ + +  String *goEnumName(Node *n) { +    String *ret = Getattr(n, "go:enumname"); +    if (ret) { +      return Copy(ret); +    } + +    if (Equal(Getattr(n, "type"), "enum ")) { +      return NewString("int"); +    } + +    String *type = Getattr(n, "enumtype"); +    assert(type); +    char *p = Char(type); +    int len = Len(type); +    String *s = NewString(""); +    bool capitalize = true; +    for (int i = 0; i < len; ++i, ++p) { +      if (*p == ':') { +	++i; +	++p; +	assert(*p == ':'); +	capitalize = true; +      } else if (capitalize) { +	Putc(toupper(*p), s); +	capitalize = false; +      } else { +	Putc(*p, s); +      } +    } + +    ret = Swig_name_mangle(s); +    Delete(s); +    return ret; +  } + + +  /* ---------------------------------------------------------------------- +   * getParm() +   * +   * Get the real parameter to use. +   * ---------------------------------------------------------------------- */ + +  Parm *getParm(Parm *p) { +    while (p && checkAttribute(p, "tmap:in:numinputs", "0")) { +      p = Getattr(p, "tmap:in:next"); +    } +    return p; +  } + +  /* ---------------------------------------------------------------------- +   * nextParm() +   * +   * Return the next parameter. +   * ---------------------------------------------------------------------- */ + +  Parm *nextParm(Parm *p) { +    if (!p) { +      return NULL; +    } else if (Getattr(p, "tmap:in")) { +      return Getattr(p, "tmap:in:next"); +    } else { +      return nextSibling(p); +    } +  } + +  /* ---------------------------------------------------------------------- +   * isStatic +   * +   * Return whether a node should be considered as static rather than +   * as a member. +   * ---------------------------------------------------------------------- */ + +  bool isStatic(Node *n) { +    String *storage = Getattr(n, "storage"); +    return (storage && (Swig_storage_isstatic(n) || Strcmp(storage, "friend") == 0) && (!SmartPointer || !Getattr(n, "allocate:smartpointeraccess"))); +  } + +  /* ---------------------------------------------------------------------- +   * isFriend +   * +   * Return whether a node is a friend. +   * ---------------------------------------------------------------------- */ + +  bool isFriend(Node *n) { +    String *storage = Getattr(n, "storage"); +    return storage && Strcmp(storage, "friend") == 0; +  } + +  /* ---------------------------------------------------------------------- +   * goGetattr +   * +   * Fetch an attribute from a node but return NULL if it is the empty string. +   * ---------------------------------------------------------------------- */ +  Node *goGetattr(Node *n, const char *name) { +    Node *ret = Getattr(n, name); +    if (ret != NULL && Len(ret) == 0) { +      ret = NULL; +    } +    return ret; +  } + +  /* ---------------------------------------------------------------------- +   * goTypemapLookup +   * +   * Look up a typemap but return NULL if it is the empty string. +   * ---------------------------------------------------------------------- */ +  String *goTypemapLookup(const char *name, Node *node, const char *lname) { +    String *ret = Swig_typemap_lookup(name, node, lname, NULL); +    if (ret != NULL && Len(ret) == 0) { +      ret = NULL; +    } +    return ret; +  } + +  /* ---------------------------------------------------------------------- +   * getModuleName +   * +   * Return the name of a module. This is different from module path: +   * "some/path/to/module" -> "module". +   * ---------------------------------------------------------------------- */ + +  String *getModuleName(String *module_path) { +    char *suffix = strrchr(Char(module_path), '/'); +    if (suffix == NULL) { +      return module_path; +    } +    return Str(suffix + 1); +  } + +};				/* class GO */ + +/* ----------------------------------------------------------------------------- + * swig_go()    - Instantiate module + * ----------------------------------------------------------------------------- */ + +static Language *new_swig_go() { +  return new GO(); +} +extern "C" Language *swig_go(void) { +  return new_swig_go(); +} + +/* ----------------------------------------------------------------------------- + * Static member variables + * ----------------------------------------------------------------------------- */ + +// Usage message. +const char * const GO::usage = "\ +Go Options (available with -go)\n\ +     -cgo                - Generate cgo input files\n\ +     -no-cgo             - Do not generate cgo input files\n\ +     -gccgo              - Generate code for gccgo rather than gc\n\ +     -go-pkgpath <p>     - Like gccgo -fgo-pkgpath option\n\ +     -go-prefix <p>      - Like gccgo -fgo-prefix option\n\ +     -import-prefix <p>  - Prefix to add to %import directives\n\ +     -intgosize <s>      - Set size of Go int type--32 or 64 bits\n\ +     -package <name>     - Set name of the Go package to <name>\n\ +     -use-shlib          - Force use of a shared library\n\ +     -soname <name>      - Set shared library holding C/C++ code to <name>\n\ +\n"; diff --git a/contrib/tools/swig/Source/Modules/guile.cxx b/contrib/tools/swig/Source/Modules/guile.cxx new file mode 100644 index 00000000000..605e0319758 --- /dev/null +++ b/contrib/tools/swig/Source/Modules/guile.cxx @@ -0,0 +1,1662 @@ +/* -----------------------------------------------------------------------------  + * This file is part of SWIG, which is licensed as a whole under version 3  + * (or any later version) of the GNU General Public License. Some additional + * terms also apply to certain portions of SWIG. The full details of the SWIG + * license and copyrights can be found in the LICENSE and COPYRIGHT files + * included with the SWIG source code as distributed by the SWIG developers + * and at https://www.swig.org/legal.html. + * + * guile.cxx + * + * Guile language module for SWIG. + * ----------------------------------------------------------------------------- */ + +#include "swigmod.h" +#include <ctype.h> + +// Note string broken in half for compilers that can't handle long strings +static const char *usage = "\ +Guile Options (available with -guile)\n\ +     -emitsetters            - Emit procedures-with-setters for variables\n\ +                               and structure slots.\n\ +     -emitslotaccessors      - Emit accessor methods for all GOOPS slots\n" "\ +     -exportprimitive        - Add the (export ...) code from scmstub into the\n\ +                               GOOPS file.\n\ +     -goopsprefix <prefix>   - Prepend <prefix> to all goops identifiers\n\ +     -Linkage <lstyle>       - Use linkage protocol <lstyle> (default `simple')\n\ +                               Use `module' for native Guile module linking\n\ +                               (requires Guile >= 1.5.0).  Use `passive' for\n\ +                               passive linking (no C-level module-handling code),\n\ +                               `ltdlmod' for Guile's old dynamic module\n\ +                               convention (Guile <= 1.4), or `hobbit' for hobbit\n\ +                               modules.\n\ +     -onlysetters            - Don't emit traditional getter and setter\n\ +                               procedures for structure slots,\n\ +                               only emit procedures-with-setters.\n\ +     -package <name>         - Set the path of the module to <name>\n\ +                               (default NULL)\n\ +     -prefix <name>          - Use <name> as prefix [default \"gswig_\"]\n\ +     -procdoc <file>         - Output procedure documentation to <file>\n\ +     -procdocformat <format> - Output procedure documentation in <format>;\n\ +                               one of `guile-1.4', `plain', `texinfo'\n\ +     -proxy                  - Export GOOPS class definitions\n\ +     -primsuffix <suffix>    - Name appended to primitive module when exporting\n\ +                               GOOPS classes. (default = \"primitive\")\n\ +     -scmstub                - Output Scheme file with module declaration and\n\ +                               exports; only with `passive' and `simple' linkage\n\ +     -useclassprefix         - Prepend the class name to all goops identifiers\n\ +\n"; + +static File *f_begin = 0; +static File *f_runtime = 0; +static File *f_header = 0; +static File *f_wrappers = 0; +static File *f_init = 0; + + +static String *prefix = NewString("gswig_"); +static char *module = 0; +static String *package = 0; +static enum { +  GUILE_LSTYLE_SIMPLE,		// call `SWIG_init()' +  GUILE_LSTYLE_PASSIVE,		// passive linking (no module code) +  GUILE_LSTYLE_MODULE,		// native guile module linking (Guile >= 1.4.1) +  GUILE_LSTYLE_LTDLMOD_1_4,	// old (Guile <= 1.4) dynamic module convention +  GUILE_LSTYLE_HOBBIT		// use (hobbit4d link) +} linkage = GUILE_LSTYLE_SIMPLE; + +static File *procdoc = 0; +static bool scmstub = false; +static String *scmtext; +static bool goops = false; +static String *goopstext; +static String *goopscode; +static String *goopsexport; + +static enum { +  GUILE_1_4, +  PLAIN, +  TEXINFO +} docformat = GUILE_1_4; + +static int emit_setters = 0; +static int only_setters = 0; +static int emit_slot_accessors = 0; +static int struct_member = 0; + +static String *beforereturn = 0; +static String *return_nothing_doc = 0; +static String *return_one_doc = 0; +static String *return_multi_doc = 0; + +static String *exported_symbols = 0; + +static int exporting_destructor = 0; +static String *swigtype_ptr = 0; + +/* GOOPS stuff */ +static String *primsuffix = 0; +static String *class_name = 0; +static String *short_class_name = 0; +static String *goops_class_methods; +static int in_class = 0; +static int have_constructor = 0; +static int useclassprefix = 0;	// -useclassprefix argument +static String *goopsprefix = 0;	// -goopsprefix argument +static int primRenamer = 0;	// if (use-modules ((...) :renamer ...) is exported to GOOPS file +static int exportprimitive = 0;	// -exportprimitive argument +static String *memberfunction_name = 0; + +extern "C" { +  static int has_classname(Node *class_node) { +    return Getattr(class_node, "guile:goopsclassname") ? 1 : 0; +  } +} + +class GUILE:public Language { +public: + +  /* ------------------------------------------------------------ +   * main() +   * ------------------------------------------------------------ */ + +  virtual void main(int argc, char *argv[]) { +    int i; + +     SWIG_library_directory("guile"); +     SWIG_typemap_lang("guile"); + +    // Look for certain command line options +    for (i = 1; i < argc; i++) { +      if (argv[i]) { +	if (strcmp(argv[i], "-help") == 0) { +	  fputs(usage, stdout); +	  Exit(EXIT_SUCCESS); +	} else if (strcmp(argv[i], "-prefix") == 0) { +	  if (argv[i + 1]) { +	    prefix = NewString(argv[i + 1]); +	    Swig_mark_arg(i); +	    Swig_mark_arg(i + 1); +	    i++; +	  } else { +	    Swig_arg_error(); +	  } +	} else if (strcmp(argv[i], "-package") == 0) { +	  if (argv[i + 1]) { +	    package = NewString(argv[i + 1]); +	    Swig_mark_arg(i); +	    Swig_mark_arg(i + 1); +	    i++; +	  } else { +	    Swig_arg_error(); +	  } +	} else if (strcmp(argv[i], "-Linkage") == 0 || strcmp(argv[i], "-linkage") == 0) { +	  if (argv[i + 1]) { +	    if (0 == strcmp(argv[i + 1], "ltdlmod")) +	      linkage = GUILE_LSTYLE_LTDLMOD_1_4; +	    else if (0 == strcmp(argv[i + 1], "hobbit")) +	      linkage = GUILE_LSTYLE_HOBBIT; +	    else if (0 == strcmp(argv[i + 1], "simple")) +	      linkage = GUILE_LSTYLE_SIMPLE; +	    else if (0 == strcmp(argv[i + 1], "passive")) +	      linkage = GUILE_LSTYLE_PASSIVE; +	    else if (0 == strcmp(argv[i + 1], "module")) +	      linkage = GUILE_LSTYLE_MODULE; +	    else +	      Swig_arg_error(); +	    Swig_mark_arg(i); +	    Swig_mark_arg(i + 1); +	    i++; +	  } else { +	    Swig_arg_error(); +	  } +	} else if (strcmp(argv[i], "-procdoc") == 0) { +	  if (argv[i + 1]) { +	    procdoc = NewFile(argv[i + 1], "w", SWIG_output_files()); +	    if (!procdoc) { +	      FileErrorDisplay(argv[i + 1]); +	      Exit(EXIT_FAILURE); +	    } +	    Swig_mark_arg(i); +	    Swig_mark_arg(i + 1); +	    i++; +	  } else { +	    Swig_arg_error(); +	  } +	} else if (strcmp(argv[i], "-procdocformat") == 0) { +	  if (strcmp(argv[i + 1], "guile-1.4") == 0) +	    docformat = GUILE_1_4; +	  else if (strcmp(argv[i + 1], "plain") == 0) +	    docformat = PLAIN; +	  else if (strcmp(argv[i + 1], "texinfo") == 0) +	    docformat = TEXINFO; +	  else +	    Swig_arg_error(); +	  Swig_mark_arg(i); +	  Swig_mark_arg(i + 1); +	  i++; +	} else if (strcmp(argv[i], "-emit-setters") == 0 || strcmp(argv[i], "-emitsetters") == 0) { +	  emit_setters = 1; +	  Swig_mark_arg(i); +	} else if (strcmp(argv[i], "-only-setters") == 0 || strcmp(argv[i], "-onlysetters") == 0) { +	  emit_setters = 1; +	  only_setters = 1; +	  Swig_mark_arg(i); +	} else if (strcmp(argv[i], "-emit-slot-accessors") == 0 || strcmp(argv[i], "-emitslotaccessors") == 0) { +	  emit_slot_accessors = 1; +	  Swig_mark_arg(i); +	} else if (strcmp(argv[i], "-scmstub") == 0) { +	  scmstub = true; +	  Swig_mark_arg(i); +	} else if ((strcmp(argv[i], "-shadow") == 0) || ((strcmp(argv[i], "-proxy") == 0))) { +	  goops = true; +	  Swig_mark_arg(i); +	} else if (strcmp(argv[i], "-gh") == 0) { +	  Printf(stderr, "Deprecated command line option: -gh. Wrappers are always generated for the SCM interface. See documentation for more information regarding the deprecated GH interface.\n"); +	  Swig_mark_arg(i); +	} else if (strcmp(argv[i], "-scm") == 0) { +	  Printf(stderr, "Deprecated command line option: -scm. Wrappers are always generated for the SCM interface. See documentation for more information regarding the deprecated GH interface.\n"); +	  Swig_mark_arg(i); +	} else if (strcmp(argv[i], "-primsuffix") == 0) { +	  if (argv[i + 1]) { +	    primsuffix = NewString(argv[i + 1]); +	    Swig_mark_arg(i); +	    Swig_mark_arg(i + 1); +	    i++; +	  } else { +	    Swig_arg_error(); +	  } +	} else if (strcmp(argv[i], "-goopsprefix") == 0) { +	  if (argv[i + 1]) { +	    goopsprefix = NewString(argv[i + 1]); +	    Swig_mark_arg(i); +	    Swig_mark_arg(i + 1); +	    i++; +	  } else { +	    Swig_arg_error(); +	  } +	} else if (strcmp(argv[i], "-useclassprefix") == 0) { +	  useclassprefix = 1; +	  Swig_mark_arg(i); +	} else if (strcmp(argv[i], "-exportprimitive") == 0) { +	  exportprimitive = 1; +	  // should use Swig_warning() here? +	  Swig_mark_arg(i); +	} +      } +    } + +    // set default value for primsuffix +    if (!primsuffix) +      primsuffix = NewString("primitive"); + +    //goops support can only be enabled if passive or module linkage is used +    if (goops) { +      if (linkage != GUILE_LSTYLE_PASSIVE && linkage != GUILE_LSTYLE_MODULE) { +	Printf(stderr, "guile: GOOPS support requires passive or module linkage\n"); +	Exit(EXIT_FAILURE); +      } +    } + +    if (goops) { +      // -proxy implies -emit-setters +      emit_setters = 1; +    } + +    if ((linkage == GUILE_LSTYLE_PASSIVE && scmstub) || linkage == GUILE_LSTYLE_MODULE) +      primRenamer = 1; + +    if (exportprimitive && primRenamer) { +      // should use Swig_warning() ? +      Printf(stderr, "guile: Warning: -exportprimitive only makes sense with passive linkage without a scmstub.\n"); +    } + +    // Make sure `prefix' ends in an underscore +    if (prefix) { +      const char *px = Char(prefix); +      if (px[Len(prefix) - 1] != '_') +	Printf(prefix, "_"); +    } + +    /* Add a symbol for this module */ +    Preprocessor_define("SWIGGUILE 1", 0); +    /* Read in default typemaps */ +    SWIG_config_file("guile_scm.swg"); +    allow_overloading(); + +  } + +  /* ------------------------------------------------------------ +   * top() +   * ------------------------------------------------------------ */ + +  virtual int top(Node *n) { +    /* Initialize all of the output files */ +    String *outfile = Getattr(n, "outfile"); + +    f_begin = NewFile(outfile, "w", SWIG_output_files()); +    if (!f_begin) { +      FileErrorDisplay(outfile); +      Exit(EXIT_FAILURE); +    } +    f_runtime = NewString(""); +    f_init = NewString(""); +    f_header = NewString(""); +    f_wrappers = NewString(""); + +    /* Register file targets with the SWIG file handler */ +    Swig_register_filebyname("header", f_header); +    Swig_register_filebyname("wrapper", f_wrappers); +    Swig_register_filebyname("begin", f_begin); +    Swig_register_filebyname("runtime", f_runtime); +    Swig_register_filebyname("init", f_init); + +    scmtext = NewString(""); +    Swig_register_filebyname("scheme", scmtext); +    exported_symbols = NewString(""); +    goopstext = NewString(""); +    Swig_register_filebyname("goops", goopstext); +    goopscode = NewString(""); +    goopsexport = NewString(""); + +    Swig_banner(f_begin); + +    Swig_obligatory_macros(f_runtime, "GUILE"); + +    /* Write out directives and declarations */ + +    module = Swig_copy_string(Char(Getattr(n, "name"))); + +    switch (linkage) { +    case GUILE_LSTYLE_SIMPLE: +      /* Simple linkage; we have to export the SWIG_init function. The user can +         rename the function by a #define. */ +      Printf(f_runtime, "#define SWIG_GUILE_INIT_STATIC extern\n"); +      break; +    default: +      /* Other linkage; we make the SWIG_init function static */ +      Printf(f_runtime, "#define SWIG_GUILE_INIT_STATIC static\n"); +      break; +    } + +    if (CPlusPlus) { +      Printf(f_runtime, "extern \"C\" {\n\n"); +    } +    Printf(f_runtime, "SWIG_GUILE_INIT_STATIC void\nSWIG_init (void);\n"); +    if (CPlusPlus) { +      Printf(f_runtime, "\n}\n"); +    } + +    Printf(f_runtime, "\n"); + +    Language::top(n); + +    /* Close module */ + +    Printf(f_wrappers, "#ifdef __cplusplus\nextern \"C\" {\n#endif\n"); + +    SwigType_emit_type_table(f_runtime, f_wrappers); + +    Printf(f_init, "}\n\n"); +    Printf(f_init, "#ifdef __cplusplus\n}\n#endif\n"); + +    String *module_name = NewString(""); + +    if (!module) +      Printv(module_name, "swig", NIL); +    else { +      if (package) +	Printf(module_name, "%s/%s", package, module); +      else +	Printv(module_name, module, NIL); +    } +    emit_linkage(module_name); + +    Delete(module_name); + +    if (procdoc) { +      Delete(procdoc); +      procdoc = NULL; +    } +    Delete(goopscode); +    Delete(goopsexport); +    Delete(goopstext); + +    /* Close all of the files */ +    Dump(f_runtime, f_begin); +    Dump(f_header, f_begin); +    Dump(f_wrappers, f_begin); +    Wrapper_pretty_print(f_init, f_begin); +    Delete(f_header); +    Delete(f_wrappers); +    Delete(f_init); +    Delete(f_runtime); +    Delete(f_begin); +    return SWIG_OK; +  } + +  void emit_linkage(String *module_name) { +    String *module_func = NewString(""); + +    if (CPlusPlus) { +      Printf(f_init, "extern \"C\" {\n\n"); +    } + +    Printv(module_func, module_name, NIL); +    Replaceall(module_func, "-", "_"); + +    switch (linkage) { +    case GUILE_LSTYLE_SIMPLE: +      Printf(f_init, "\n/* Linkage: simple */\n"); +      break; +    case GUILE_LSTYLE_PASSIVE: +      Printf(f_init, "\n/* Linkage: passive */\n"); +      Replaceall(module_func, "/", "_"); +      Insert(module_func, 0, "scm_init_"); +      Append(module_func, "_module"); + +      Printf(f_init, "SCM\n%s (void)\n{\n", module_func); +      Printf(f_init, "  SWIG_init();\n"); +      Printf(f_init, "  return SCM_UNSPECIFIED;\n"); +      Printf(f_init, "}\n"); +      break; +    case GUILE_LSTYLE_LTDLMOD_1_4: +      Printf(f_init, "\n/* Linkage: ltdlmod */\n"); +      Replaceall(module_func, "/", "_"); +      Insert(module_func, 0, "scm_init_"); +      Append(module_func, "_module"); +      Printf(f_init, "SCM\n%s (void)\n{\n", module_func); +      { +	String *mod = NewString(module_name); +	Replaceall(mod, "/", " "); +	Printf(f_init, "    scm_register_module_xxx (\"%s\", (void *) SWIG_init);\n", mod); +	Printf(f_init, "    return SCM_UNSPECIFIED;\n"); +	Delete(mod); +      } +      Printf(f_init, "}\n"); +      break; +    case GUILE_LSTYLE_MODULE: +      Printf(f_init, "\n/* Linkage: module */\n"); +      Replaceall(module_func, "/", "_"); +      Insert(module_func, 0, "scm_init_"); +      Append(module_func, "_module"); + +      Printf(f_init, "static void SWIG_init_helper(void *data)\n"); +      Printf(f_init, "{\n    SWIG_init();\n"); +      if (Len(exported_symbols) > 0) +	Printf(f_init, "    scm_c_export(%sNULL);", exported_symbols); +      Printf(f_init, "\n}\n\n"); + +      Printf(f_init, "SCM\n%s (void)\n{\n", module_func); +      { +	String *mod = NewString(module_name); +	if (goops) +	  Printv(mod, "-", primsuffix, NIL); +	Replaceall(mod, "/", " "); +	Printf(f_init, "    scm_c_define_module(\"%s\",\n", mod); +	Printf(f_init, "      SWIG_init_helper, NULL);\n"); +	Printf(f_init, "    return SCM_UNSPECIFIED;\n"); +	Delete(mod); +      } +      Printf(f_init, "}\n"); +      break; +    case GUILE_LSTYLE_HOBBIT: +      Printf(f_init, "\n/* Linkage: hobbit */\n"); +      Replaceall(module_func, "/", "_slash_"); +      Insert(module_func, 0, "scm_init_"); +      Printf(f_init, "SCM\n%s (void)\n{\n", module_func); +      { +	String *mod = NewString(module_name); +	Replaceall(mod, "/", " "); +	Printf(f_init, "    scm_register_module_xxx (\"%s\", (void *) SWIG_init);\n", mod); +	Printf(f_init, "    return SCM_UNSPECIFIED;\n"); +	Delete(mod); +      } +      Printf(f_init, "}\n"); +      break; +    default: +      fputs("Fatal internal error: Invalid Guile linkage setting.\n", stderr); +      Exit(EXIT_FAILURE); +    } + +    if (scmstub) { +      /* Emit Scheme stub if requested */ +      String *primitive_name = NewString(module_name); +      if (goops) +	Printv(primitive_name, "-", primsuffix, NIL); + +      String *mod = NewString(primitive_name); +      Replaceall(mod, "/", " "); + +      String *fname = NewStringf("%s%s.scm", +				 SWIG_output_directory(), +				 primitive_name); +      Delete(primitive_name); +      File *scmstubfile = NewFile(fname, "w", SWIG_output_files()); +      if (!scmstubfile) { +	FileErrorDisplay(fname); +	Exit(EXIT_FAILURE); +      } +      Delete(fname); + +      Swig_banner_target_lang(scmstubfile, ";;;"); +      Printf(scmstubfile, "\n"); +      if (linkage == GUILE_LSTYLE_SIMPLE || linkage == GUILE_LSTYLE_PASSIVE) +	Printf(scmstubfile, "(define-module (%s))\n\n", mod); +      Delete(mod); +      Printf(scmstubfile, "%s", scmtext); +      if ((linkage == GUILE_LSTYLE_SIMPLE || linkage == GUILE_LSTYLE_PASSIVE) +	  && Len(exported_symbols) > 0) { +	String *ex = NewString(exported_symbols); +	Replaceall(ex, ", ", "\n        "); +	Replaceall(ex, "\"", ""); +	Chop(ex); +	Printf(scmstubfile, "\n(export %s)\n", ex); +	Delete(ex); +      } +      Delete(scmstubfile); +    } + +    if (goops) { +      String *mod = NewString(module_name); +      Replaceall(mod, "/", " "); + +      String *fname = NewStringf("%s%s.scm", SWIG_output_directory(), +				 module_name); +      File *goopsfile = NewFile(fname, "w", SWIG_output_files()); +      if (!goopsfile) { +	FileErrorDisplay(fname); +	Exit(EXIT_FAILURE); +      } +      Delete(fname); +      Swig_banner_target_lang(goopsfile, ";;;"); +      Printf(goopsfile, "\n"); +      Printf(goopsfile, "(define-module (%s))\n", mod); +      Printf(goopsfile, "%s\n", goopstext); +      Printf(goopsfile, "(use-modules (oop goops) (Swig common))\n"); +      if (primRenamer) { +	Printf(goopsfile, "(use-modules ((%s-%s) :renamer (symbol-prefix-proc 'primitive:)))\n", mod, primsuffix); +      } +      Printf(goopsfile, "%s\n(export %s)", goopscode, goopsexport); +      if (exportprimitive) { +	String *ex = NewString(exported_symbols); +	Replaceall(ex, ", ", "\n        "); +	Replaceall(ex, "\"", ""); +	Chop(ex); +	Printf(goopsfile, "\n(export %s)", ex); +	Delete(ex); +      } +      Delete(mod); +      Delete(goopsfile); +    } + +    Delete(module_func); +    if (CPlusPlus) { +      Printf(f_init, "\n}\n"); +    } +  } + +  /* Return true iff T is a pointer type */ + +  int is_a_pointer(SwigType *t) { +    return SwigType_ispointer(SwigType_typedef_resolve_all(t)); +  } + +  /* Report an error handling the given type. */ + +  void throw_unhandled_guile_type_error(SwigType *d) { +    Swig_warning(WARN_TYPEMAP_UNDEF, input_file, line_number, "Unable to handle type %s.\n", SwigType_str(d, 0)); +  } + +  /* Write out procedure documentation */ + +  void write_doc(const String *proc_name, const String *signature, const String *doc, const String *signature2 = NULL) { +    switch (docformat) { +    case GUILE_1_4: +      Printv(procdoc, "\f\n", NIL); +      Printv(procdoc, "(", signature, ")\n", NIL); +      if (signature2) +	Printv(procdoc, "(", signature2, ")\n", NIL); +      Printv(procdoc, doc, "\n", NIL); +      break; +    case PLAIN: +      Printv(procdoc, "\f", proc_name, "\n\n", NIL); +      Printv(procdoc, "(", signature, ")\n", NIL); +      if (signature2) +	Printv(procdoc, "(", signature2, ")\n", NIL); +      Printv(procdoc, doc, "\n\n", NIL); +      break; +    case TEXINFO: +      Printv(procdoc, "\f", proc_name, "\n", NIL); +      Printv(procdoc, "@deffn primitive ", signature, "\n", NIL); +      if (signature2) +	Printv(procdoc, "@deffnx primitive ", signature2, "\n", NIL); +      Printv(procdoc, doc, "\n", NIL); +      Printv(procdoc, "@end deffn\n\n", NIL); +      break; +    } +  } + +  /* returns false if the typemap is an empty string */ +  bool handle_documentation_typemap(String *output, +				    const String *maybe_delimiter, Parm *p, const String *typemap, const String *default_doc, const String *name = NULL) { +    String *tmp = NewString(""); +    String *tm; +    if (!(tm = Getattr(p, typemap))) { +      Printf(tmp, "%s", default_doc); +      tm = tmp; +    } +    bool result = (Len(tm) > 0); +    if (maybe_delimiter && Len(output) > 0 && Len(tm) > 0) { +      Printv(output, maybe_delimiter, NIL); +    } +    const String *pn = !name ? (const String *) Getattr(p, "name") : name; +    String *pt = Getattr(p, "type"); +    Replaceall(tm, "$name", pn);	// legacy for $parmname +    Replaceall(tm, "$type", SwigType_str(pt, 0)); +    /* $NAME is like $name, but marked-up as a variable. */ +    String *ARGNAME = NewString(""); +    if (docformat == TEXINFO) +      Printf(ARGNAME, "@var{%s}", pn); +    else +      Printf(ARGNAME, "%(upper)s", pn); +    Replaceall(tm, "$NAME", ARGNAME); +    Replaceall(tm, "$PARMNAME", ARGNAME); +    Printv(output, tm, NIL); +    Delete(tmp); +    return result; +  } + +  /* ------------------------------------------------------------ +   * functionWrapper() +   * Create a function declaration and register it with the interpreter. +   * ------------------------------------------------------------ */ + +  virtual int functionWrapper(Node *n) { +    String *iname = Getattr(n, "sym:name"); +    SwigType *d = Getattr(n, "type"); +    ParmList *l = Getattr(n, "parms"); +    Parm *p; +    String *proc_name = 0; +    char source[256]; +    Wrapper *f = NewWrapper(); +    String *cleanup = NewString(""); +    String *outarg = NewString(""); +    String *signature = NewString(""); +    String *doc_body = NewString(""); +    String *returns = NewString(""); +    String *method_signature = NewString(""); +    String *primitive_args = NewString(""); +    Hash *scheme_arg_names = NewHash(); +    int num_results = 1; +    String *tmp = NewString(""); +    String *tm; +    int i; +    int numargs = 0; +    int numreq = 0; +    String *overname = 0; +    int args_passed_as_array = 0; +    int scheme_argnum = 0; +    bool any_specialized_arg = false; + +    // Make a wrapper name for this +    String *wname = Swig_name_wrapper(iname); +    if (Getattr(n, "sym:overloaded")) { +      overname = Getattr(n, "sym:overname"); +      args_passed_as_array = 1; +    } else { +      if (!addSymbol(iname, n)) { +        DelWrapper(f); +	return SWIG_ERROR;  +      } +    } +    if (overname) { +      Append(wname, overname); +    } +    Setattr(n, "wrap:name", wname); + +    // Build the name for scheme. +    proc_name = NewString(iname); +    Replaceall(proc_name, "_", "-"); + +    /* Emit locals etc. into f->code; figure out which args to ignore */ +    emit_parameter_variables(l, f); + +    /* Attach the standard typemaps */ +    emit_attach_parmmaps(l, f); +    Setattr(n, "wrap:parms", l); + +    /* Get number of required and total arguments */ +    numargs = emit_num_arguments(l); +    numreq = emit_num_required(l); + +    /* Declare return variable */ + +    Wrapper_add_local(f, "gswig_result", "SCM gswig_result"); +    Wrapper_add_local(f, "gswig_list_p", "SWIGUNUSED int gswig_list_p = 0"); + +    /* Open prototype and signature */ + +    Printv(f->def, "static SCM\n", wname, " (", NIL); +    if (args_passed_as_array) { +      Printv(f->def, "int argc, SCM *argv", NIL); +    } +    Printv(signature, proc_name, NIL); + +    /* Now write code to extract the parameters */ + +    for (i = 0, p = l; i < numargs; i++) { + +      while (checkAttribute(p, "tmap:in:numinputs", "0")) { +	p = Getattr(p, "tmap:in:next"); +      } + +      SwigType *pt = Getattr(p, "type"); +      int opt_p = (i >= numreq); + +      // Produce names of source and target +      if (args_passed_as_array) +	sprintf(source, "argv[%d]", i); +      else +	sprintf(source, "s_%d", i); + +      if (!args_passed_as_array) { +	if (i != 0) +	  Printf(f->def, ", "); +	Printf(f->def, "SCM s_%d", i); +      } +      if (opt_p) { +	Printf(f->code, "    if (%s != SCM_UNDEFINED) {\n", source); +      } +      if ((tm = Getattr(p, "tmap:in"))) { +	Replaceall(tm, "$input", source); +	Setattr(p, "emit:input", source); +	Printv(f->code, tm, "\n", NIL); + +	SwigType *pb = SwigType_typedef_resolve_all(SwigType_base(pt)); +	SwigType *pn = Getattr(p, "name"); +	String *argname; +	scheme_argnum++; +	if (pn && !Getattr(scheme_arg_names, pn)) +	  argname = pn; +	else { +	  /* Anonymous arg or re-used argument name -- choose a name that cannot clash */ +	  argname = NewStringf("%%arg%d", scheme_argnum); +	} + +	if (procdoc) { +	  if (i == numreq) { +	    /* First optional argument */ +	    Printf(signature, " #:optional"); +	  } +	  /* Add to signature (arglist) */ +	  handle_documentation_typemap(signature, " ", p, "tmap:in:arglist", "$name", argname); +	  /* Document the type of the arg in the documentation body */ +	  handle_documentation_typemap(doc_body, ", ", p, "tmap:in:doc", "$NAME is of type <$type>", argname); +	} + +	if (goops) { +	  if (i < numreq) { +	    if (strcmp("void", Char(pt)) != 0) { +	      Node *class_node = Swig_symbol_clookup_check(pb, Getattr(n, "sym:symtab"), +							   has_classname); +	      String *goopsclassname = !class_node ? NULL : Getattr(class_node, "guile:goopsclassname"); +	      /* do input conversion */ +	      if (goopsclassname) { +		Printv(method_signature, " (", argname, " ", goopsclassname, ")", NIL); +		any_specialized_arg = true; +	      } else { +		Printv(method_signature, " ", argname, NIL); +	      } +	      Printv(primitive_args, " ", argname, NIL); +	      Setattr(scheme_arg_names, argname, p); +	    } +	  } +	} + +	if (!pn) { +	  Delete(argname); +	} +	p = Getattr(p, "tmap:in:next"); +      } else { +	throw_unhandled_guile_type_error(pt); +	p = nextSibling(p); +      } +      if (opt_p) +	Printf(f->code, "    }\n"); +    } +    if (Len(doc_body) > 0) +      Printf(doc_body, ".\n"); + +    /* Insert constraint checking code */ +    for (p = l; p;) { +      if ((tm = Getattr(p, "tmap:check"))) { +	Printv(f->code, tm, "\n", NIL); +	p = Getattr(p, "tmap:check:next"); +      } else { +	p = nextSibling(p); +      } +    } +    /* Pass output arguments back to the caller. */ + +    /* Insert argument output code */ +    String *returns_argout = NewString(""); +    for (p = l; p;) { +      if ((tm = Getattr(p, "tmap:argout"))) { +	Replaceall(tm, "$arg", Getattr(p, "emit:input")); +	Replaceall(tm, "$input", Getattr(p, "emit:input")); +	Printv(outarg, tm, "\n", NIL); +	if (procdoc) { +	  if (handle_documentation_typemap(returns_argout, ", ", p, "tmap:argout:doc", "$NAME (of type $type)")) { +	    /* A documentation typemap that is not the empty string +	       indicates that a value is returned to Scheme. */ +	    num_results++; +	  } +	} +	p = Getattr(p, "tmap:argout:next"); +      } else { +	p = nextSibling(p); +      } +    } + +    /* Insert cleanup code */ +    for (p = l; p;) { +      if ((tm = Getattr(p, "tmap:freearg"))) { +	Replaceall(tm, "$input", Getattr(p, "emit:input")); +	Printv(cleanup, tm, "\n", NIL); +	p = Getattr(p, "tmap:freearg:next"); +      } else { +	p = nextSibling(p); +      } +    } + +    if (exporting_destructor) { +      /* Mark the destructor's argument as destroyed. */ +      String *tm = NewString("SWIG_Guile_MarkPointerDestroyed($input);"); +      Replaceall(tm, "$input", Getattr(l, "emit:input")); +      Printv(cleanup, tm, "\n", NIL); +      Delete(tm); +    } + +    /* Close prototype */ + +    Printf(f->def, ")\n{\n"); + +    /* Define the scheme name in C. This define is used by several Guile +       macros. */ +    Printv(f->def, "#define FUNC_NAME \"", proc_name, "\"", NIL); + +    // Now write code to make the function call +    String *actioncode = emit_action(n); + +    // Now have return value, figure out what to do with it. +    if ((tm = Swig_typemap_lookup_out("out", n, Swig_cresult_name(), f, actioncode))) { +      Replaceall(tm, "$result", "gswig_result"); +      if (GetFlag(n, "feature:new")) +	Replaceall(tm, "$owner", "1"); +      else +	Replaceall(tm, "$owner", "0"); +      Printv(f->code, tm, "\n", NIL); +    } else { +      throw_unhandled_guile_type_error(d); +    } +    emit_return_variable(n, d, f); + +    // Documentation +    if ((tm = Getattr(n, "tmap:out:doc"))) { +      Printv(returns, tm, NIL); +      if (Len(tm) > 0) +	num_results = 1; +      else +	num_results = 0; +    } else { +      String *s = SwigType_str(d, 0); +      Chop(s); +      Printf(returns, "<%s>", s); +      Delete(s); +      num_results = 1; +    } +    Append(returns, returns_argout); + + +    // Dump the argument output code +    Printv(f->code, outarg, NIL); + +    // Dump the argument cleanup code +    Printv(f->code, cleanup, NIL); + +    // Look for any remaining cleanup + +    if (GetFlag(n, "feature:new")) { +      if ((tm = Swig_typemap_lookup("newfree", n, Swig_cresult_name(), 0))) { +	Printv(f->code, tm, "\n", NIL); +      } +    } +    // Free any memory allocated by the function being wrapped.. +    if ((tm = Swig_typemap_lookup("ret", n, Swig_cresult_name(), 0))) { +      Printv(f->code, tm, "\n", NIL); +    } +    // Wrap things up (in a manner of speaking) + +    if (beforereturn) +      Printv(f->code, beforereturn, "\n", NIL); +    Printv(f->code, "return gswig_result;\n", NIL); + +    /* Substitute the function name */ +    Replaceall(f->code, "$symname", iname); +    // Undefine the scheme name + +    Printf(f->code, "#undef FUNC_NAME\n"); +    Printf(f->code, "}\n"); + +    Wrapper_print(f, f_wrappers); + +    if (!Getattr(n, "sym:overloaded")) { +      if (numargs > 10) { +	int i; +	/* gh_new_procedure would complain: too many args */ +	/* Build a wrapper wrapper */ +	Printv(f_wrappers, "static SCM\n", wname, "_rest (SCM rest)\n", NIL); +	Printv(f_wrappers, "{\n", NIL); +	Printf(f_wrappers, "SCM arg[%d];\n", numargs); +	Printf(f_wrappers, "SWIG_Guile_GetArgs (arg, rest, %d, %d, \"%s\");\n", numreq, numargs - numreq, proc_name); +	Printv(f_wrappers, "return ", wname, "(", NIL); +	Printv(f_wrappers, "arg[0]", NIL); +	for (i = 1; i < numargs; i++) +	  Printf(f_wrappers, ", arg[%d]", i); +	Printv(f_wrappers, ");\n", NIL); +	Printv(f_wrappers, "}\n", NIL); +	/* Register it */ +	Printf(f_init, "scm_c_define_gsubr(\"%s\", 0, 0, 1, (swig_guile_proc) %s_rest);\n", proc_name, wname); +      } else if (emit_setters && struct_member && strlen(Char(proc_name)) > 3) { +	int len = Len(proc_name); +	const char *pc = Char(proc_name); +	/* MEMBER-set and MEMBER-get functions. */ +	int is_setter = (pc[len - 3] == 's'); +	if (is_setter) { +	  Printf(f_init, "SCM setter = "); +	  struct_member = 2;	/* have a setter */ +	} else +	  Printf(f_init, "SCM getter = "); +	/* GOOPS support uses the MEMBER-set and MEMBER-get functions, +	   so ignore only_setters in this case. */ +	if (only_setters && !goops) +	  Printf(f_init, "scm_c_make_gsubr(\"%s\", %d, %d, 0, (swig_guile_proc) %s);\n", proc_name, numreq, numargs - numreq, wname); +	else +	  Printf(f_init, "scm_c_define_gsubr(\"%s\", %d, %d, 0, (swig_guile_proc) %s);\n", proc_name, numreq, numargs - numreq, wname); + +	if (!is_setter) { +	  /* Strip off "-get" */ +	  if (struct_member == 2) { +	    /* There was a setter, so create a procedure with setter */ +	    Printf(f_init, "scm_c_define"); +	    Printf(f_init, "(\"%.*s\", " "scm_make_procedure_with_setter(getter, setter));\n", pc, len - 4); +	  } else { +	    /* There was no setter, so make an alias to the getter */ +	    Printf(f_init, "scm_c_define"); +	    Printf(f_init, "(\"%.*s\", getter);\n", pc, len - 4); +	  } +	  Printf(exported_symbols, "\"%.*s\", ", pc, len - 4); +	} +      } else { +	/* Register the function */ +	if (exporting_destructor) { +	  Printf(f_init, "((swig_guile_clientdata *)(SWIGTYPE%s->clientdata))->destroy = (guile_destructor) %s;\n", swigtype_ptr, wname); +	  //Printf(f_init, "SWIG_TypeClientData(SWIGTYPE%s, (void *) %s);\n", swigtype_ptr, wname); +	} +	Printf(f_init, "scm_c_define_gsubr(\"%s\", %d, %d, 0, (swig_guile_proc) %s);\n", proc_name, numreq, numargs - numreq, wname); +      } +    } else {			/* overloaded function; don't export the single methods */ +      if (!Getattr(n, "sym:nextSibling")) { +	/* Emit overloading dispatch function */ + +	int maxargs; +	String *dispatch = Swig_overload_dispatch(n, "return %s(argc,argv);", &maxargs); + +	/* Generate a dispatch wrapper for all overloaded functions */ + +	Wrapper *df = NewWrapper(); +	String *dname = Swig_name_wrapper(iname); + +	Printv(df->def, "static SCM\n", dname, "(SCM rest)\n{\n", NIL); +	Printf(df->code, "#define FUNC_NAME \"%s\"\n", proc_name); +	Printf(df->code, "SCM argv[%d];\n", maxargs); +	Printf(df->code, "int argc = SWIG_Guile_GetArgs (argv, rest, %d, %d, \"%s\");\n", 0, maxargs, proc_name); +	Printv(df->code, dispatch, "\n", NIL); +	Printf(df->code, "scm_misc_error(\"%s\", \"No matching method for generic function `%s'\", SCM_EOL);\n", proc_name, iname); +	Printf(df->code, "#undef FUNC_NAME\n"); +	Printv(df->code, "}\n", NIL); +	Wrapper_print(df, f_wrappers); +	Printf(f_init, "scm_c_define_gsubr(\"%s\", 0, 0, 1, (swig_guile_proc) %s);\n", proc_name, dname); +	DelWrapper(df); +	Delete(dispatch); +	Delete(dname); +      } +    } +    Printf(exported_symbols, "\"%s\", ", proc_name); + +    if (!in_class || memberfunction_name) { +      // export wrapper into goops file +      String *method_def = NewString(""); +      String *goops_name; +      if (in_class) +	goops_name = NewString(memberfunction_name); +      else +	goops_name = goopsNameMapping(proc_name, ""); +      String *primitive_name = NewString(""); +      if (primRenamer) +	Printv(primitive_name, "primitive:", proc_name, NIL); +      else +	Printv(primitive_name, proc_name, NIL); +      Replaceall(method_signature, "_", "-"); +      Replaceall(primitive_args, "_", "-"); +      if (!any_specialized_arg) { +	/* If there would not be any specialized argument in +	   the method declaration, we simply re-export the +	   function.  This is a performance optimization. */ +	Printv(method_def, "(define ", goops_name, " ", primitive_name, ")\n", NIL); +      } else if (numreq == numargs) { +	Printv(method_def, "(define-method (", goops_name, method_signature, ")\n", NIL); +	Printv(method_def, "  (", primitive_name, primitive_args, "))\n", NIL); +      } else { +	/* Handle optional args. For the rest argument, use a name +	   that cannot clash. */ +	Printv(method_def, "(define-method (", goops_name, method_signature, " . %args)\n", NIL); +	Printv(method_def, "  (apply ", primitive_name, primitive_args, " %args))\n", NIL); +      } +      if (in_class) { +	/* Defer method definition till end of class definition. */ +	Printv(goops_class_methods, method_def, NIL); +      } else { +	Printv(goopscode, method_def, NIL); +      } +      Printf(goopsexport, "%s ", goops_name); +      Delete(primitive_name); +      Delete(goops_name); +      Delete(method_def); +    } + +    if (procdoc) { +      String *returns_text = NewString(""); +      if (num_results == 0) +	Printv(returns_text, return_nothing_doc, NIL); +      else if (num_results == 1) +	Printv(returns_text, return_one_doc, NIL); +      else +	Printv(returns_text, return_multi_doc, NIL); +      /* Substitute documentation variables */ +      static const char *numbers[] = { "zero", "one", "two", "three", +	"four", "five", "six", "seven", +	"eight", "nine", "ten", "eleven", +	"twelve" +      }; +      if (num_results <= 12) +	Replaceall(returns_text, "$num_values", numbers[num_results]); +      else { +	String *num_results_str = NewStringf("%d", num_results); +	Replaceall(returns_text, "$num_values", num_results_str); +	Delete(num_results_str); +      } +      Replaceall(returns_text, "$values", returns); +      Printf(doc_body, "\n%s", returns_text); +      write_doc(proc_name, signature, doc_body); +      Delete(returns_text); +    } + +    Delete(proc_name); +    Delete(outarg); +    Delete(cleanup); +    Delete(signature); +    Delete(method_signature); +    Delete(primitive_args); +    Delete(doc_body); +    Delete(returns_argout); +    Delete(returns); +    Delete(tmp); +    Delete(scheme_arg_names); +    DelWrapper(f); +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * variableWrapper() +   * +   * Create a link to a C variable. +   * This creates a single function PREFIX_var_VARNAME(). +   * This function takes a single optional argument.   If supplied, it means +   * we are setting this variable to some value.  If omitted, it means we are +   * simply evaluating this variable.  Either way, we return the variables +   * value. +   * ------------------------------------------------------------ */ + +  virtual int variableWrapper(Node *n) { + +    char *name = GetChar(n, "name"); +    char *iname = GetChar(n, "sym:name"); +    SwigType *t = Getattr(n, "type"); + +    String *proc_name; +    Wrapper *f; +    String *tm; + +    if (!addSymbol(iname, n)) +      return SWIG_ERROR; + +    f = NewWrapper(); +    // evaluation function names + +    String *var_name = Swig_name_wrapper(iname); + +    // Build the name for scheme. +    proc_name = NewString(iname); +    Replaceall(proc_name, "_", "-"); +    Setattr(n, "wrap:name", proc_name); + +    if (1 || (SwigType_type(t) != T_USER) || (is_a_pointer(t))) { + +      Printf(f->def, "static SCM\n%s(SCM s_0)\n{\n", var_name); + +      /* Define the scheme name in C. This define is used by several Guile +         macros. */ +      Printv(f->def, "#define FUNC_NAME \"", proc_name, "\"", NIL); + +      Wrapper_add_local(f, "gswig_result", "SCM gswig_result"); + +      if (!GetFlag(n, "feature:immutable")) { +	/* Check for a setting of the variable value */ +	Printf(f->code, "if (s_0 != SCM_UNDEFINED) {\n"); +	if ((tm = Swig_typemap_lookup("varin", n, name, 0))) { +	  Replaceall(tm, "$input", "s_0"); +	  /* Printv(f->code,tm,"\n",NIL); */ +	  emit_action_code(n, f->code, tm); +	} else { +	  throw_unhandled_guile_type_error(t); +	} +	Printf(f->code, "}\n"); +      } +      // Now return the value of the variable (regardless +      // of evaluating or setting) + +      if ((tm = Swig_typemap_lookup("varout", n, name, 0))) { +	Replaceall(tm, "$result", "gswig_result"); +	/* Printv(f->code,tm,"\n",NIL); */ +	emit_action_code(n, f->code, tm); +      } else { +	throw_unhandled_guile_type_error(t); +      } +      Printf(f->code, "\nreturn gswig_result;\n"); +      Printf(f->code, "#undef FUNC_NAME\n"); +      Printf(f->code, "}\n"); + +      Wrapper_print(f, f_wrappers); + +      // Now add symbol to the Guile interpreter + +      if (!emit_setters || GetFlag(n, "feature:immutable")) { +	/* Read-only variables become a simple procedure returning the +	   value; read-write variables become a simple procedure with +	   an optional argument. */ + +	if (!goops && GetFlag(n, "feature:constasvar")) { +	  /* need to export this function as a variable instead of a procedure */ +	  if (scmstub) { +	    /* export the function in the wrapper, and (set!) it in scmstub */ +	    Printf(f_init, "scm_c_define_gsubr(\"%s\", 0, %d, 0, (swig_guile_proc) %s);\n", proc_name, !GetFlag(n, "feature:immutable"), var_name); +	    Printf(scmtext, "(set! %s (%s))\n", proc_name, proc_name); +	  } else { +	    /* export the variable directly */ +	    Printf(f_init, "scm_c_define(\"%s\", %s(SCM_UNDEFINED));\n", proc_name, var_name); +	  } + +	} else { +	  /* Export the function as normal */ +	  Printf(f_init, "scm_c_define_gsubr(\"%s\", 0, %d, 0, (swig_guile_proc) %s);\n", proc_name, !GetFlag(n, "feature:immutable"), var_name); +	} + +      } else { +	/* Read/write variables become a procedure with setter. */ +	Printf(f_init, "{ SCM p = scm_c_define_gsubr(\"%s\", 0, 1, 0, (swig_guile_proc) %s);\n", proc_name, var_name); +	Printf(f_init, "scm_c_define"); +	Printf(f_init, "(\"%s\", " "scm_make_procedure_with_setter(p, p)); }\n", proc_name); +      } +      Printf(exported_symbols, "\"%s\", ", proc_name); + +      // export wrapper into goops file +      if (!in_class) {		// only if the variable is not part of a class +	String *class_name = SwigType_typedef_resolve_all(SwigType_base(t)); +	String *goops_name = goopsNameMapping(proc_name, ""); +	String *primitive_name = NewString(""); +	if (primRenamer) +	  Printv(primitive_name, "primitive:", NIL); +	Printv(primitive_name, proc_name, NIL); +	/* Simply re-export the procedure */ +	if ((!emit_setters || GetFlag(n, "feature:immutable")) +	    && GetFlag(n, "feature:constasvar")) { +	  Printv(goopscode, "(define ", goops_name, " (", primitive_name, "))\n", NIL); +	} else { +	  Printv(goopscode, "(define ", goops_name, " ", primitive_name, ")\n", NIL); +	} +	Printf(goopsexport, "%s ", goops_name); +	Delete(primitive_name); +	Delete(class_name); +	Delete(goops_name); +      } + +      if (procdoc) { +	/* Compute documentation */ +	String *signature = NewString(""); +	String *signature2 = NULL; +	String *doc = NewString(""); + +	if (GetFlag(n, "feature:immutable")) { +	  Printv(signature, proc_name, NIL); +	  if (GetFlag(n, "feature:constasvar")) { +	    Printv(doc, "Is constant ", NIL); +	  } else { +	    Printv(doc, "Returns constant ", NIL); +	  } +	  if ((tm = Getattr(n, "tmap:varout:doc"))) { +	    Printv(doc, tm, NIL); +	  } else { +	    String *s = SwigType_str(t, 0); +	    Chop(s); +	    Printf(doc, "<%s>", s); +	    Delete(s); +	  } +	} else if (emit_setters) { +	  Printv(signature, proc_name, NIL); +	  signature2 = NewString(""); +	  Printv(signature2, "set! (", proc_name, ") ", NIL); +	  handle_documentation_typemap(signature2, NIL, n, "tmap:varin:arglist", "new-value"); +	  Printv(doc, "Get or set the value of the C variable, \n", NIL); +	  Printv(doc, "which is of type ", NIL); +	  handle_documentation_typemap(doc, NIL, n, "tmap:varout:doc", "$1_type"); +	  Printv(doc, "."); +	} else { +	  Printv(signature, proc_name, " #:optional ", NIL); +	  if ((tm = Getattr(n, "tmap:varin:doc"))) { +	    Printv(signature, tm, NIL); +	  } else { +	    String *s = SwigType_str(t, 0); +	    Chop(s); +	    Printf(signature, "new-value <%s>", s); +	    Delete(s); +	  } + +	  Printv(doc, "If NEW-VALUE is provided, " "set C variable to this value.\n", NIL); +	  Printv(doc, "Returns variable value ", NIL); +	  if ((tm = Getattr(n, "tmap:varout:doc"))) { +	    Printv(doc, tm, NIL); +	  } else { +	    String *s = SwigType_str(t, 0); +	    Chop(s); +	    Printf(doc, "<%s>", s); +	    Delete(s); +	  } +	} +	write_doc(proc_name, signature, doc, signature2); +	Delete(signature); +	if (signature2) +	  Delete(signature2); +	Delete(doc); +      } + +    } else { +      Swig_warning(WARN_TYPEMAP_VAR_UNDEF, input_file, line_number, "Unsupported variable type %s (ignored).\n", SwigType_str(t, 0)); +    } +    Delete(var_name); +    Delete(proc_name); +    DelWrapper(f); +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * constantWrapper() +   * +   * We create a read-only variable. +   * ------------------------------------------------------------ */ + +  virtual int constantWrapper(Node *n) { +    char *name = GetChar(n, "name"); +    char *iname = GetChar(n, "sym:name"); +    SwigType *type = Getattr(n, "type"); +    String *rawval = Getattr(n, "rawval"); +    String *value = rawval ? rawval : Getattr(n, "value"); +    int constasvar = GetFlag(n, "feature:constasvar"); + + +    String *proc_name; +    String *var_name; +    Wrapper *f; +    SwigType *nctype; +    String *tm; + +    f = NewWrapper(); + +    // Make a static variable; +    var_name = NewStringf("%sconst_%s", prefix, iname); + +    // Strip const qualifier from type if present + +    nctype = NewString(type); +    if (SwigType_isconst(nctype)) { +      Delete(SwigType_pop(nctype)); +    } +    // Build the name for scheme. +    proc_name = NewString(iname); +    Replaceall(proc_name, "_", "-"); + +    if ((SwigType_type(nctype) == T_USER) && (!is_a_pointer(nctype))) { +      Swig_warning(WARN_TYPEMAP_CONST_UNDEF, input_file, line_number, "Unsupported constant value.\n"); +      Delete(var_name); +      DelWrapper(f); +      return SWIG_NOWRAP; +    } +    // See if there's a typemap + +    if ((tm = Swig_typemap_lookup("constant", n, name, 0))) { +      Replaceall(tm, "$value", value); +      Printv(f_header, tm, "\n", NIL); +    } else { +      // Create variable and assign it a value +      Printf(f_header, "static %s = (%s)(%s);\n", SwigType_str(type, var_name), SwigType_str(type, 0), value); +    } +    { +      /* Hack alert: will cleanup later -- Dave */ +      Node *nn = NewHash(); +      Setfile(nn, Getfile(n)); +      Setline(nn, Getline(n)); +      Setattr(nn, "name", var_name); +      Setattr(nn, "sym:name", iname); +      Setattr(nn, "type", nctype); +      SetFlag(nn, "feature:immutable"); +      if (constasvar) { +	SetFlag(nn, "feature:constasvar"); +      } +      variableWrapper(nn); +      Delete(nn); +    } +    Delete(var_name); +    Delete(nctype); +    Delete(proc_name); +    DelWrapper(f); +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * classDeclaration() +   * ------------------------------------------------------------ */ +  virtual int classDeclaration(Node *n) { +    String *class_name = NewStringf("<%s>", Getattr(n, "sym:name")); +    Setattr(n, "guile:goopsclassname", class_name); +    return Language::classDeclaration(n); +  } + +  /* ------------------------------------------------------------ +   * classHandler() +   * ------------------------------------------------------------ */ +  virtual int classHandler(Node *n) { +    /* Create new strings for building up a wrapper function */ +    have_constructor = 0; + +    class_name = NewString(""); +    short_class_name = NewString(""); +    Printv(class_name, "<", Getattr(n, "sym:name"), ">", NIL); +    Printv(short_class_name, Getattr(n, "sym:name"), NIL); +    Replaceall(class_name, "_", "-"); +    Replaceall(short_class_name, "_", "-"); + +    if (!addSymbol(class_name, n)) +      return SWIG_ERROR; + +    /* Handle inheritance */ +    String *base_class = NewString("<"); +    List *baselist = Getattr(n, "bases"); +    if (baselist && Len(baselist)) { +      Iterator i = First(baselist); +      while (i.item) { +	Printv(base_class, Getattr(i.item, "sym:name"), NIL); +	i = Next(i); +	if (i.item) { +	  Printf(base_class, "> <"); +	} +      } +    } +    Printf(base_class, ">"); +    Replaceall(base_class, "_", "-"); + +    Printv(goopscode, "(define-class ", class_name, " ", NIL); +    Printf(goopsexport, "%s ", class_name); + +    if (Len(base_class) > 2) { +      Printv(goopscode, "(", base_class, ")\n", NIL); +    } else { +      Printv(goopscode, "(<swig>)\n", NIL); +    } +    SwigType *ct = NewStringf("p.%s", Getattr(n, "name")); +    swigtype_ptr = SwigType_manglestr(ct); + +    String *mangled_classname = Swig_name_mangle(Getattr(n, "sym:name")); +    /* Export clientdata structure */ +    Printf(f_runtime, "static swig_guile_clientdata _swig_guile_clientdata%s = { NULL, SCM_EOL };\n", mangled_classname); + +    Printv(f_init, "SWIG_TypeClientData(SWIGTYPE", swigtype_ptr, ", (void *) &_swig_guile_clientdata", mangled_classname, ");\n", NIL); +    SwigType_remember(ct); +    Delete(ct); + +    /* Emit all of the members */ +    goops_class_methods = NewString(""); + +    in_class = 1; +    Language::classHandler(n); +    in_class = 0; + +    Printv(goopscode, "  #:metaclass <swig-metaclass>\n", NIL); + +    if (have_constructor) +      Printv(goopscode, "  #:new-function ", primRenamer ? "primitive:" : "", "new-", short_class_name, "\n", NIL); + +    Printf(goopscode, ")\n%s\n", goops_class_methods); +    Delete(goops_class_methods); +    goops_class_methods = 0; + + +    /* export class initialization function */ +    if (goops) { +      /* export the wrapper function */ +      String *funcName = NewString(mangled_classname); +      Printf(funcName, "_swig_guile_setgoopsclass"); +      String *guileFuncName = NewString(funcName); +      Replaceall(guileFuncName, "_", "-"); + +      Printv(f_wrappers, "static SCM ", funcName, "(SCM cl) \n", NIL); +      Printf(f_wrappers, "#define FUNC_NAME %s\n{\n", guileFuncName); +      Printv(f_wrappers, "  ((swig_guile_clientdata *)(SWIGTYPE", swigtype_ptr, "->clientdata))->goops_class = cl;\n", NIL); +      Printf(f_wrappers, "  return SCM_UNSPECIFIED;\n"); +      Printf(f_wrappers, "}\n#undef FUNC_NAME\n\n"); + +      Printf(f_init, "scm_c_define_gsubr(\"%s\", 1, 0, 0, (swig_guile_proc) %s);\n", guileFuncName, funcName); +      Printf(exported_symbols, "\"%s\", ", guileFuncName); + +      /* export the call to the wrapper function */ +      Printf(goopscode, "(%s%s %s)\n\n", primRenamer ? "primitive:" : "", guileFuncName, class_name); + +      Delete(guileFuncName); +      Delete(funcName); +    } + +    Delete(mangled_classname); + +    Delete(swigtype_ptr); +    swigtype_ptr = 0; + +    Delete(class_name); +    Delete(short_class_name); +    class_name = 0; +    short_class_name = 0; + +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * memberfunctionHandler() +   * ------------------------------------------------------------ */ +  int memberfunctionHandler(Node *n) { +    String *iname = Getattr(n, "sym:name"); +    String *proc = NewString(iname); +    Replaceall(proc, "_", "-"); + +    memberfunction_name = goopsNameMapping(proc, short_class_name); +    Language::memberfunctionHandler(n); +    Delete(memberfunction_name); +    memberfunction_name = NULL; +    Delete(proc); +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * membervariableHandler() +   * ------------------------------------------------------------ */ +  int membervariableHandler(Node *n) { +    String *iname = Getattr(n, "sym:name"); + +    if (emit_setters) { +      struct_member = 1; +      Printf(f_init, "{\n"); +    } + +    Language::membervariableHandler(n); + +    if (emit_setters) { +      Printf(f_init, "}\n"); +      struct_member = 0; +    } + +    String *proc = NewString(iname); +    Replaceall(proc, "_", "-"); +    String *goops_name = goopsNameMapping(proc, short_class_name); + +    /* The slot name is never qualified with the class, +       even if useclassprefix is true. */ +    Printv(goopscode, "  (", proc, " #:allocation #:virtual", NIL); +    /* GOOPS (at least in Guile 1.6.3) only accepts closures, not +       primitive procedures for slot-ref and slot-set. */ +    Printv(goopscode, "\n   #:slot-ref (lambda (obj) (", primRenamer ? "primitive:" : "", short_class_name, "-", proc, "-get", " obj))", NIL); +    if (!GetFlag(n, "feature:immutable")) { +      Printv(goopscode, "\n   #:slot-set! (lambda (obj value) (", primRenamer ? "primitive:" : "", short_class_name, "-", proc, "-set", " obj value))", NIL); +    } else { +      Printf(goopscode, "\n   #:slot-set! (lambda (obj value) (error \"Immutable slot\"))"); +    } +    if (emit_slot_accessors) { +      if (GetFlag(n, "feature:immutable")) { +	Printv(goopscode, "\n   #:getter ", goops_name, NIL); +      } else { +	Printv(goopscode, "\n   #:accessor ", goops_name, NIL); +      } +      Printf(goopsexport, "%s ", goops_name); +    } +    Printv(goopscode, ")\n", NIL); +    Delete(proc); +    Delete(goops_name); +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * constructorHandler() +   * ------------------------------------------------------------ */ +  int constructorHandler(Node *n) { +    Language::constructorHandler(n); +    have_constructor = 1; +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * destructorHandler() +   * ------------------------------------------------------------ */ +  virtual int destructorHandler(Node *n) { +    exporting_destructor = true; +    Language::destructorHandler(n); +    exporting_destructor = false; +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * pragmaDirective() +   * ------------------------------------------------------------ */ + +  virtual int pragmaDirective(Node *n) { +    if (!ImportMode) { +      String *lang = Getattr(n, "lang"); +      String *cmd = Getattr(n, "name"); +      String *value = Getattr(n, "value"); + +#     define store_pragma(PRAGMANAME)			\ +        if (Strcmp(cmd, #PRAGMANAME) == 0) {		\ +	  if (PRAGMANAME) Delete(PRAGMANAME);		\ +	  PRAGMANAME = value ? NewString(value) : NULL;	\ +	} + +      if (Strcmp(lang, "guile") == 0) { +	store_pragma(beforereturn) +	    store_pragma(return_nothing_doc) +	    store_pragma(return_one_doc) +	    store_pragma(return_multi_doc); +#     undef store_pragma +      } +    } +    return Language::pragmaDirective(n); +  } + + +  /* ------------------------------------------------------------ +   * goopsNameMapping() +   * Maps the identifier from C++ to the GOOPS based * on command  +   * line parameters and such. +   * If class_name = "" that means the mapping is for a function or +   * variable not attached to any class. +   * ------------------------------------------------------------ */ +  String *goopsNameMapping(String *name, const_String_or_char_ptr class_name) { +    String *n = NewString(""); + +    if (Strcmp(class_name, "") == 0) { +      // not part of a class, so no class name to prefix +      if (goopsprefix) { +	Printf(n, "%s%s", goopsprefix, name); +      } else { +	Printf(n, "%s", name); +      } +    } else { +      if (useclassprefix) { +	Printf(n, "%s-%s", class_name, name); +      } else { +	if (goopsprefix) { +	  Printf(n, "%s%s", goopsprefix, name); +	} else { +	  Printf(n, "%s", name); +	} +      } +    } +    return n; +  } + + +  /* ------------------------------------------------------------ +   * validIdentifier() +   * ------------------------------------------------------------ */ + +  virtual int validIdentifier(String *s) { +    char *c = Char(s); +    /* Check whether we have an R5RS identifier.  Guile supports a +       superset of R5RS identifiers, but it's probably a bad idea to use +       those. */ +    /* <identifier> --> <initial> <subsequent>* | <peculiar identifier> */ +    /* <initial> --> <letter> | <special initial> */ +    if (!(isalpha(*c) || (*c == '!') || (*c == '$') || (*c == '%') +	  || (*c == '&') || (*c == '*') || (*c == '/') || (*c == ':') +	  || (*c == '<') || (*c == '=') || (*c == '>') || (*c == '?') +	  || (*c == '^') || (*c == '_') || (*c == '~'))) { +      /* <peculiar identifier> --> + | - | ... */ +      if ((strcmp(c, "+") == 0) +	  || strcmp(c, "-") == 0 || strcmp(c, "...") == 0) +	return 1; +      else +	return 0; +    } +    /* <subsequent> --> <initial> | <digit> | <special subsequent> */ +    while (*c) { +      if (!(isalnum(*c) || (*c == '!') || (*c == '$') || (*c == '%') +	    || (*c == '&') || (*c == '*') || (*c == '/') || (*c == ':') +	    || (*c == '<') || (*c == '=') || (*c == '>') || (*c == '?') +	    || (*c == '^') || (*c == '_') || (*c == '~') || (*c == '+') +	    || (*c == '-') || (*c == '.') || (*c == '@'))) +	return 0; +      c++; +    } +    return 1; +  } + +  String *runtimeCode() { +    String *s; +    s = Swig_include_sys("guile_scm_run.swg"); +    if (!s) { +      Printf(stderr, "*** Unable to open 'guile_scm_run.swg"); +      s = NewString(""); +    } +    return s; +  } + +  String *defaultExternalRuntimeFilename() { +    return NewString("swigguilerun.h"); +  } +}; + +/* ----------------------------------------------------------------------------- + * swig_guile()    - Instantiate module + * ----------------------------------------------------------------------------- */ + +static Language *new_swig_guile() { +  return new GUILE(); +} +extern "C" Language *swig_guile(void) { +  return new_swig_guile(); +} diff --git a/contrib/tools/swig/Source/Modules/interface.cxx b/contrib/tools/swig/Source/Modules/interface.cxx new file mode 100644 index 00000000000..83a5e5f8a13 --- /dev/null +++ b/contrib/tools/swig/Source/Modules/interface.cxx @@ -0,0 +1,210 @@ +/* -----------------------------------------------------------------------------  + * This file is part of SWIG, which is licensed as a whole under version 3  + * (or any later version) of the GNU General Public License. Some additional + * terms also apply to certain portions of SWIG. The full details of the SWIG + * license and copyrights can be found in the LICENSE and COPYRIGHT files + * included with the SWIG source code as distributed by the SWIG developers + * and at https://www.swig.org/legal.html. + * + * interface.cxx + * + * This module contains support for the interface feature. + * This feature is used in language modules where the target language does not + * naturally support C++ style multiple inheritance, but does support inheritance  + * from multiple interfaces. + * ----------------------------------------------------------------------------- */ + +#include "swigmod.h" +#include "cparse.h" + +static bool interface_feature_enabled = false; + +/* ----------------------------------------------------------------------------- + * collect_interface_methods() + * + * Create a list of all the methods from the base classes of class n that are + * marked as an interface. The resulting list is thus the list of methods that + * need to be implemented in order for n to be non-abstract. + * ----------------------------------------------------------------------------- */ + +static List *collect_interface_methods(Node *n) { +  List *methods = NewList(); +  if (List *bases = Getattr(n, "interface:bases")) { +    for (Iterator base = First(bases); base.item; base = Next(base)) { +      Node *cls = base.item; +      if (cls == n) +	continue; +      for (Node *child = firstChild(cls); child; child = nextSibling(child)) { +	if (Cmp(nodeType(child), "cdecl") == 0) { +	  if (GetFlag(child, "feature:ignore") || Getattr(child, "interface:owner")) +	    continue; // skip methods propagated to bases +	  if (!checkAttribute(child, "kind", "function")) +	    continue; +	  if (checkAttribute(child, "storage", "static")) +	    continue; // accept virtual methods, non-virtual methods too... mmm??. Warn that the interface class has something that is not a virtual method? +	  Node *nn = copyNode(child); +	  Setattr(nn, "interface:owner", cls); +	  ParmList *parms = CopyParmList(Getattr(child, "parms")); +	  Setattr(nn, "parms", parms); +	  Delete(parms); +	  ParmList *throw_parm_list = Getattr(child, "throws"); +	  if (throw_parm_list) +	    Setattr(nn, "throws", CopyParmList(throw_parm_list)); +	  Append(methods, nn); +	} +      } +    } +  } +  return methods; +} + +/* ----------------------------------------------------------------------------- + * collect_interface_bases + * ----------------------------------------------------------------------------- */ + +static void collect_interface_bases(List *bases, Node *n) { +  if (GetFlag(n, "feature:interface")) { +    String *name = Getattr(n, "interface:name"); +    if (!Getattr(bases, name)) +      Append(bases, n); +  } + +  if (List *baselist = Getattr(n, "bases")) { +    for (Iterator base = First(baselist); base.item; base = Next(base)) { +      if (!GetFlag(base.item, "feature:ignore")) { +	if (GetFlag(base.item, "feature:interface")) +	  collect_interface_bases(bases, base.item); +      } +    } +  } +} + +/* ----------------------------------------------------------------------------- + * collect_interface_base_classes() + * + * Create a hash containing all the classes up the inheritance hierarchy + * marked with feature:interface (including this class n). + * Stops going up the inheritance chain as soon as a class is found without + * feature:interface. + * The idea is to find all the base interfaces that a class must implement. + * ----------------------------------------------------------------------------- */ + +static void collect_interface_base_classes(Node *n) { +  if (GetFlag(n, "feature:interface")) { +    // check all bases are also interfaces +    if (List *baselist = Getattr(n, "bases")) { +      for (Iterator base = First(baselist); base.item; base = Next(base)) { +	if (!GetFlag(base.item, "feature:ignore")) { +	  if (!GetFlag(base.item, "feature:interface")) { +	    Swig_error(Getfile(n), Getline(n), "Base class '%s' of '%s' is not similarly marked as an interface.\n", SwigType_namestr(Getattr(base.item, "name")), SwigType_namestr(Getattr(n, "name"))); +	    Exit(EXIT_FAILURE); +	  } +	} +      } +    } +  } + +  List *interface_bases = NewList(); +  collect_interface_bases(interface_bases, n); +  if (Len(interface_bases) == 0) +    Delete(interface_bases); +  else +    Setattr(n, "interface:bases", interface_bases); +} + +/* ----------------------------------------------------------------------------- + * process_interface_name() + * ----------------------------------------------------------------------------- */ + +static void process_interface_name(Node *n) { +  if (GetFlag(n, "feature:interface")) { +    String *interface_name = Getattr(n, "feature:interface:name"); +    if (!Len(interface_name)) { +      Swig_error(Getfile(n), Getline(n), "The interface feature for '%s' is missing the name attribute.\n", SwigType_namestr(Getattr(n, "name"))); +      Exit(EXIT_FAILURE); +    } +    if (Strchr(interface_name, '%')) { +      String *name = NewStringf(interface_name, Getattr(n, "sym:name")); +      Setattr(n, "interface:name", name); +    } else { +      Setattr(n, "interface:name", interface_name); +    } +  } +} + +/* ----------------------------------------------------------------------------- + * Swig_interface_propagate_methods() + * + * Find all the base classes marked as an interface (with feature:interface) for + * class node n. For each of these, add all of its methods as methods of n so that + * n is not abstract. If class n is also marked as an interface, it will remain + * abstract and not have any methods added. + * ----------------------------------------------------------------------------- */ + +void Swig_interface_propagate_methods(Node *n) { +  if (interface_feature_enabled) { +    process_interface_name(n); +    collect_interface_base_classes(n); +    List *methods = collect_interface_methods(n); +    bool is_interface = GetFlag(n, "feature:interface") ? true : false; +    for (Iterator mi = First(methods); mi.item; mi = Next(mi)) { +      if (!is_interface && GetFlag(mi.item, "abstract")) +	continue; +      String *this_decl = Getattr(mi.item, "decl"); +      String *this_decl_resolved = SwigType_typedef_resolve_all(this_decl); +      bool identically_overloaded_method = false; // true when a base class' method is implemented in n +      if (SwigType_isfunction(this_decl_resolved)) { +	String *name = Getattr(mi.item, "name"); +	for (Node *child = firstChild(n); child; child = nextSibling(child)) { +	  if (Getattr(child, "interface:owner")) +	    break; // at the end of the list are newly appended methods +	  if (Cmp(nodeType(child), "cdecl") == 0) { +	    if (checkAttribute(child, "name", name)) { +	      String *decl = SwigType_typedef_resolve_all(Getattr(child, "decl")); +	      identically_overloaded_method = Strcmp(decl, this_decl_resolved) == 0; +	      Delete(decl); +	      if (identically_overloaded_method) +		break; +	    } +	  } +	} +      } +      Delete(this_decl_resolved); +      if (!identically_overloaded_method) { +	// Add method copied from base class to this derived class +	Node *cn = mi.item; +	Delattr(cn, "sym:overname"); +	String *prefix = Getattr(n, "name"); +	String *name = Getattr(cn, "name"); +	String *decl = Getattr(cn, "decl"); +	String *oldname = Getattr(cn, "sym:name"); + +	String *symname = Swig_name_make(cn, prefix, name, decl, oldname); +	if (Strcmp(symname, "$ignore") != 0) { +	  Symtab *oldscope = Swig_symbol_setscope(Getattr(n, "symtab")); +	  Node *on = Swig_symbol_add(symname, cn); +	  (void)on; +	  assert(on == cn); + +	  // Features from the copied base class method are already present, now add in features specific to the added method in the derived class +	  Swig_features_get(Swig_cparse_features(), Swig_symbol_qualifiedscopename(0), name, decl, cn); +	  Swig_symbol_setscope(oldscope); +	  appendChild(n, cn); +	} +      } else { +	Delete(mi.item); +      } +    } +    Delete(methods); +  } +} + +/* ----------------------------------------------------------------------------- + * Swig_interface_feature_enable() + * + * Turn on interface feature support + * ----------------------------------------------------------------------------- */ + +void Swig_interface_feature_enable() { +  interface_feature_enabled = true; +} diff --git a/contrib/tools/swig/Source/Modules/java.cxx b/contrib/tools/swig/Source/Modules/java.cxx new file mode 100644 index 00000000000..773945af207 --- /dev/null +++ b/contrib/tools/swig/Source/Modules/java.cxx @@ -0,0 +1,4979 @@ +/* ----------------------------------------------------------------------------- + * This file is part of SWIG, which is licensed as a whole under version 3  + * (or any later version) of the GNU General Public License. Some additional + * terms also apply to certain portions of SWIG. The full details of the SWIG + * license and copyrights can be found in the LICENSE and COPYRIGHT files + * included with the SWIG source code as distributed by the SWIG developers + * and at https://www.swig.org/legal.html. + * + * java.cxx + * + * Java language module for SWIG. + * ----------------------------------------------------------------------------- */ + +#include "swigmod.h" +#include "cparse.h" +#include <limits.h>		// for INT_MAX +#include <ctype.h> +#include "javadoc.h" + +/* Hash type used for upcalls from C/C++ */ +typedef DOH UpcallData; + +class JAVA:public Language { +  static const char *usage; +  const String *empty_string; +  const String *public_string; +  const String *protected_string; + +  Hash *swig_types_hash; +  File *f_begin; +  File *f_runtime; +  File *f_runtime_h; +  File *f_header; +  File *f_wrappers; +  File *f_init; +  File *f_directors; +  File *f_directors_h; +  List *filenames_list; + +  bool proxy_flag;		// Flag for generating proxy classes +  bool nopgcpp_flag;		// Flag for suppressing the premature garbage collection prevention parameter +  bool native_function_flag;	// Flag for when wrapping a native function +  bool enum_constant_flag;	// Flag for when wrapping an enum or constant +  bool static_flag;		// Flag for when wrapping a static functions or member variables +  bool variable_wrapper_flag;	// Flag for when wrapping a nonstatic member variable +  bool wrapping_member_flag;	// Flag for when wrapping a member variable/enum/const +  bool global_variable_flag;	// Flag for when wrapping a global variable +  bool old_variable_names;	// Flag for old style variable names in the intermediary class +  bool member_func_flag;	// flag set when wrapping a member function +  bool doxygen;			//flag for converting found doxygen to javadoc +  bool comment_creation_chatter; //flag for getting information about where comments were created in java.cxx +   +  String *imclass_name;		// intermediary class name +  String *module_class_name;	// module class name +  String *constants_interface_name;	// constants interface name +  String *imclass_class_code;	// intermediary class code +  String *proxy_class_def; +  String *proxy_class_code; +  String *interface_class_code; // if %feature("interface") was declared for a class, here goes the interface declaration +  String *module_class_code; +  String *proxy_class_name;	// proxy class name +  String *full_proxy_class_name;// fully qualified proxy class name when using nspace feature, otherwise same as proxy_class_name +  String *full_imclass_name;	// fully qualified intermediary class name when using nspace feature, otherwise same as imclass_name +  String *variable_name;	//Name of a variable being wrapped +  String *proxy_class_constants_code; +  String *module_class_constants_code; +  String *enum_code; +  String *package;		// Optional package name +  String *jnipackage;		// Package name used in the JNI code +  String *package_path;		// Package name used internally by JNI (slashes) +  String *imclass_imports;	//intermediary class imports from %pragma +  String *module_imports;	//module imports from %pragma +  String *imclass_baseclass;	//inheritance for intermediary class class from %pragma +  String *imclass_package;	//package in which to generate the intermediary class +  String *module_baseclass;	//inheritance for module class from %pragma +  String *imclass_interfaces;	//interfaces for intermediary class class from %pragma +  String *module_interfaces;	//interfaces for module class from %pragma +  String *imclass_class_modifiers;	//class modifiers for intermediary class overridden by %pragma +  String *module_class_modifiers;	//class modifiers for module class overridden by %pragma +  String *upcasts_code;		//C++ casts for inheritance hierarchies C++ code +  String *imclass_cppcasts_code;	//C++ casts up inheritance hierarchies intermediary class code +  String *imclass_directors;	// Intermediate class director code +  String *destructor_call;	//C++ destructor call if any +  String *destructor_throws_clause;	//C++ destructor throws clause if any + +  // Director method stuff: +  List *dmethods_seq; +  Hash *dmethods_table; +  int n_dmethods; +  int n_directors; +  int first_class_dmethod; +  int curr_class_dmethod; +  int nesting_depth; + +  enum EnumFeature { SimpleEnum, TypeunsafeEnum, TypesafeEnum, ProperEnum }; + +public: + +  /* ----------------------------------------------------------------------------- +   * JAVA() +   * ----------------------------------------------------------------------------- */ + +   JAVA():empty_string(NewString("")), +      public_string(NewString("public")), +      protected_string(NewString("protected")), +      swig_types_hash(NULL), +      f_begin(NULL), +      f_runtime(NULL), +      f_runtime_h(NULL), +      f_header(NULL), +      f_wrappers(NULL), +      f_init(NULL), +      f_directors(NULL), +      f_directors_h(NULL), +      filenames_list(NULL), +      proxy_flag(true), +      nopgcpp_flag(false), +      native_function_flag(false), +      enum_constant_flag(false), +      static_flag(false), +      variable_wrapper_flag(false), +      wrapping_member_flag(false), +      global_variable_flag(false), +      old_variable_names(false), +      member_func_flag(false), +      doxygen(false), +      comment_creation_chatter(false), +      imclass_name(NULL), +      module_class_name(NULL), +      constants_interface_name(NULL), +      imclass_class_code(NULL), +      proxy_class_def(NULL), +      proxy_class_code(NULL), +      interface_class_code(NULL), +      module_class_code(NULL), +      proxy_class_name(NULL), +      full_proxy_class_name(NULL), +      full_imclass_name(NULL), +      variable_name(NULL), +      proxy_class_constants_code(NULL), +      module_class_constants_code(NULL), +      enum_code(NULL), +      package(NULL), +      jnipackage(NULL), +      package_path(NULL), +      imclass_imports(NULL), +      module_imports(NULL), +      imclass_baseclass(NULL), +      imclass_package(NULL), +      module_baseclass(NULL), +      imclass_interfaces(NULL), +      module_interfaces(NULL), +      imclass_class_modifiers(NULL), +      module_class_modifiers(NULL), +      upcasts_code(NULL), +      imclass_cppcasts_code(NULL), +      imclass_directors(NULL), +      destructor_call(NULL), +      destructor_throws_clause(NULL), +      dmethods_seq(NULL), +      dmethods_table(NULL), +      n_dmethods(0), +      n_directors(0), +      first_class_dmethod(0), +      curr_class_dmethod(0), +      nesting_depth(0){ +    /* for now, multiple inheritance in directors is disabled, this +       should be easy to implement though */ +    director_multiple_inheritance = 0; +    director_language = 1; +  } +   +  ~JAVA() { +    delete doxygenTranslator; +  } + +  /* ----------------------------------------------------------------------------- +   * constructIntermediateClassName() +   * +   * Construct the fully qualified name of the intermediate class and set +   * the full_imclass_name attribute accordingly. +   * ----------------------------------------------------------------------------- */ +  void constructIntermediateClassName(Node *n) { +    String *nspace = Getattr(n, "sym:nspace"); + +    if (imclass_package && package) +      full_imclass_name = NewStringf("%s.%s.%s", package, imclass_package, imclass_name); +    else if (package && nspace) +      full_imclass_name = NewStringf("%s.%s", package, imclass_name); +    else if (imclass_package) +      full_imclass_name = NewStringf("%s.%s", imclass_package, imclass_name); +    else +      full_imclass_name = NewStringf("%s", imclass_name); + +    if (nspace && !package) { +      String *name = Getattr(n, "name") ? Getattr(n, "name") : NewString("<unnamed>"); +      Swig_warning(WARN_JAVA_NSPACE_WITHOUT_PACKAGE, Getfile(n), Getline(n), +	  "The nspace feature is used on '%s' without -package. " +	  "The generated code may not compile as Java does not support types declared in a named package accessing types declared in an unnamed package.\n", SwigType_namestr(name)); +    } +  } + +  /* ----------------------------------------------------------------------------- +   * getProxyName() +   * +   * Test to see if a type corresponds to something wrapped with a proxy class. +   * Return NULL if not otherwise the proxy class name, fully qualified with +   * package name if the nspace feature is used, unless jnidescriptor is true as +   * the package name is handled differently (unfortunately for legacy reasons). +   * ----------------------------------------------------------------------------- */ +   +   String *getProxyName(SwigType *t, bool jnidescriptor = false) { +     String *proxyname = NULL; +     if (proxy_flag) { +       Node *n = classLookup(t); +       if (n) { +	 proxyname = Getattr(n, "proxyname"); +	 if (!proxyname || jnidescriptor) { +	   String *nspace = Getattr(n, "sym:nspace"); +	   String *symname = Copy(Getattr(n, "sym:name")); +	   if (symname && !GetFlag(n, "feature:flatnested")) { +             for (Node *outer_class = Getattr(n, "nested:outer"); outer_class; outer_class = Getattr(outer_class, "nested:outer")) { +               if (String* name = Getattr(outer_class, "sym:name")) { +                 Push(symname, jnidescriptor ? "$" : "."); +                 Push(symname, name); +               } +               else +                 return NULL; +             } +	   } +	   if (nspace) { +	     if (package && !jnidescriptor) +	       proxyname = NewStringf("%s.%s.%s", package, nspace, symname); +	     else +	       proxyname = NewStringf("%s.%s", nspace, symname); +	   } else { +	     proxyname = Copy(symname); +	   } +	   if (!jnidescriptor) { +	     Setattr(n, "proxyname", proxyname); // Cache it +	     Delete(proxyname); +	   } +	   Delete(symname); +	 } +       } +     } +     return proxyname; +   } + +  /* ----------------------------------------------------------------------------- +   * makeValidJniName() +   * ----------------------------------------------------------------------------- */ + +  String *makeValidJniName(const String *name) { +    String *valid_jni_name = NewString(name); +    Replaceall(valid_jni_name, "_", "_1"); +    return valid_jni_name; +  } + +  /* ------------------------------------------------------------ +   * main() +   * ------------------------------------------------------------ */ + +  virtual void main(int argc, char *argv[]) { + +    SWIG_library_directory("java"); + +    int doxygen_translator_flags = 0; + +    // Look for certain command line options +    for (int i = 1; i < argc; i++) { +      if (argv[i]) { +	if (strcmp(argv[i], "-package") == 0) { +	  if (argv[i + 1]) { +	    package = NewString(""); +	    Printf(package, argv[i + 1]); +	    if (Len(package) == 0) { +	      Delete(package); +	      package = 0; +	    } +	    Swig_mark_arg(i); +	    Swig_mark_arg(i + 1); +	    i++; +	  } else { +	    Swig_arg_error(); +	  } +	} else if ((strcmp(argv[i], "-shadow") == 0) || ((strcmp(argv[i], "-proxy") == 0))) { +	  Printf(stderr, "Deprecated command line option: %s. Proxy classes are now generated by default.\n", argv[i]); +	  Swig_mark_arg(i); +	  proxy_flag = true; +	} else if ((strcmp(argv[i], "-doxygen") == 0)) { +	  Swig_mark_arg(i); +	  doxygen = true; +	  scan_doxygen_comments = true; +	} else if ((strcmp(argv[i], "-debug-doxygen-translator") == 0)) { +	  Swig_mark_arg(i); +	  doxygen_translator_flags |= DoxygenTranslator::debug_translator; +	} else if ((strcmp(argv[i], "-debug-doxygen-parser") == 0)) { +	  Swig_mark_arg(i); +	  doxygen_translator_flags |= DoxygenTranslator::debug_parser; +	} else if ((strcmp(argv[i], "-noproxy") == 0)) { +	  Swig_mark_arg(i); +	  proxy_flag = false; +	} else if (strcmp(argv[i], "-nopgcpp") == 0) { +	  Swig_mark_arg(i); +	  nopgcpp_flag = true; +	} else if (strcmp(argv[i], "-oldvarnames") == 0) { +	  Swig_mark_arg(i); +	  old_variable_names = true; +	} else if (strcmp(argv[i], "-jnic") == 0) { +	  Swig_mark_arg(i); +	  Printf(stderr, "Deprecated command line option: -jnic. C JNI calling convention now used when -c++ not specified.\n"); +	} else if (strcmp(argv[i], "-nofinalize") == 0) { +	  Swig_mark_arg(i); +	  Printf(stderr, "Deprecated command line option: -nofinalize. Use the new javafinalize typemap instead.\n"); +	} else if (strcmp(argv[i], "-jnicpp") == 0) { +	  Swig_mark_arg(i); +	  Printf(stderr, "Deprecated command line option: -jnicpp. C++ JNI calling convention now used when -c++ specified.\n"); +	} else if (strcmp(argv[i], "-help") == 0) { +	  Printf(stdout, "%s\n", usage); +	} +      } +    } +     +    if (doxygen) +      doxygenTranslator = new JavaDocConverter(doxygen_translator_flags); + +    // Add a symbol to the parser for conditional compilation +    Preprocessor_define("SWIGJAVA 1", 0); + +    // Add typemap definitions +    SWIG_typemap_lang("java"); +    SWIG_config_file("java.swg"); + +    allow_overloading(); +    Swig_interface_feature_enable(); +  } + +  /* --------------------------------------------------------------------- +   * top() +   * --------------------------------------------------------------------- */ + +  virtual int top(Node *n) { + +    // Get any options set in the module directive +    Node *optionsnode = Getattr(Getattr(n, "module"), "options"); + +    if (optionsnode) { +      if (Getattr(optionsnode, "jniclassname")) +	imclass_name = Copy(Getattr(optionsnode, "jniclassname")); +      /* check if directors are enabled for this module.  note: this  +       * is a "master" switch, without which no director code will be +       * emitted.  %feature("director") statements are also required +       * to enable directors for individual classes or methods. +       * +       * use %module(directors="1") modulename at the start of the  +       * interface file to enable director generation. +       */ +      if (Getattr(optionsnode, "directors")) { +	allow_directors(); +      } +      if (Getattr(optionsnode, "dirprot")) { +	allow_dirprot(); +      } +      allow_allprotected(GetFlag(optionsnode, "allprotected")); +    } + +    /* Initialize all of the output files */ +    String *outfile = Getattr(n, "outfile"); +    String *outfile_h = Getattr(n, "outfile_h"); + +    if (!outfile) { +      Printf(stderr, "Unable to determine outfile\n"); +      Exit(EXIT_FAILURE); +    } + +    f_begin = NewFile(outfile, "w", SWIG_output_files()); +    if (!f_begin) { +      FileErrorDisplay(outfile); +      Exit(EXIT_FAILURE); +    } + +    if (directorsEnabled()) { +      if (!outfile_h) { +        Printf(stderr, "Unable to determine outfile_h\n"); +	Exit(EXIT_FAILURE); +      } +      f_runtime_h = NewFile(outfile_h, "w", SWIG_output_files()); +      if (!f_runtime_h) { +	FileErrorDisplay(outfile_h); +	Exit(EXIT_FAILURE); +      } +    } + +    f_runtime = NewString(""); +    f_init = NewString(""); +    f_header = NewString(""); +    f_wrappers = NewString(""); +    f_directors_h = NewString(""); +    f_directors = NewString(""); + +    /* Register file targets with the SWIG file handler */ +    Swig_register_filebyname("begin", f_begin); +    Swig_register_filebyname("header", f_header); +    Swig_register_filebyname("wrapper", f_wrappers); +    Swig_register_filebyname("runtime", f_runtime); +    Swig_register_filebyname("init", f_init); +    Swig_register_filebyname("director", f_directors); +    Swig_register_filebyname("director_h", f_directors_h); + +    swig_types_hash = NewHash(); +    filenames_list = NewList(); + +    // Make the intermediary class and module class names. The intermediary class name can be set in the module directive. +    if (!imclass_name) { +      imclass_name = NewStringf("%sJNI", Getattr(n, "name")); +      module_class_name = Copy(Getattr(n, "name")); +    } else { +      // Rename the module name if it is the same as intermediary class name - a backwards compatibility solution +      if (Cmp(imclass_name, Getattr(n, "name")) == 0) +	module_class_name = NewStringf("%sModule", Getattr(n, "name")); +      else +	module_class_name = Copy(Getattr(n, "name")); +    } +    constants_interface_name = NewStringf("%sConstants", module_class_name); + +    // module class and intermediary classes are always created +    if (!addSymbol(imclass_name, n)) +      return SWIG_ERROR; +    if (!addSymbol(module_class_name, n)) +      return SWIG_ERROR; + +    imclass_class_code = NewString(""); +    proxy_class_def = NewString(""); +    proxy_class_code = NewString(""); +    module_class_constants_code = NewString(""); +    imclass_baseclass = NewString(""); +    imclass_package = NULL; +    imclass_interfaces = NewString(""); +    imclass_class_modifiers = NewString(""); +    module_class_code = NewString(""); +    module_baseclass = NewString(""); +    module_interfaces = NewString(""); +    module_imports = NewString(""); +    module_class_modifiers = NewString(""); +    imclass_imports = NewString(""); +    imclass_cppcasts_code = NewString(""); +    imclass_directors = NewString(""); +    upcasts_code = NewString(""); +    dmethods_seq = NewList(); +    dmethods_table = NewHash(); +    n_dmethods = 0; +    n_directors = 0; +    jnipackage = NewString(""); +    package_path = NewString(""); + +    Swig_banner(f_begin); + +    Swig_obligatory_macros(f_runtime, "JAVA"); + +    if (directorsEnabled()) { +      Printf(f_runtime, "#define SWIG_DIRECTORS\n"); + +      /* Emit initial director header and director code: */ +      Swig_banner(f_directors_h); +      Printf(f_directors_h, "\n"); +      Printf(f_directors_h, "#ifndef SWIG_%s_WRAP_H_\n", module_class_name); +      Printf(f_directors_h, "#define SWIG_%s_WRAP_H_\n\n", module_class_name); + +      Printf(f_directors, "\n\n"); +      Printf(f_directors, "/* ---------------------------------------------------\n"); +      Printf(f_directors, " * C++ director class methods\n"); +      Printf(f_directors, " * --------------------------------------------------- */\n\n"); +      if (outfile_h) { +	String *filename = Swig_file_filename(outfile_h); +	Printf(f_directors, "#include \"%s\"\n\n", filename); +	Delete(filename); +      } +    } + +    Printf(f_runtime, "\n"); + +    String *wrapper_name = NewString(""); + +    if (package) { +      String *jniname = makeValidJniName(package); +      Printv(jnipackage, jniname, NIL); +      Delete(jniname); +      Replaceall(jnipackage, ".", "_"); +      Append(jnipackage, "_"); +      Printv(package_path, package, NIL); +      Replaceall(package_path, ".", "/"); +    } +    String *jniname = makeValidJniName(imclass_name); +    Printf(wrapper_name, "Java_%s%s_%%f", jnipackage, jniname); +    Delete(jniname); + +    Swig_name_register("wrapper", Char(wrapper_name)); +    if (old_variable_names) { +      Swig_name_register("set", "set_%n%v"); +      Swig_name_register("get", "get_%n%v"); +    } + +    Delete(wrapper_name); + +    Printf(f_wrappers, "\n#ifdef __cplusplus\n"); +    Printf(f_wrappers, "extern \"C\" {\n"); +    Printf(f_wrappers, "#endif\n\n"); + +    /* Emit code */ +    Language::top(n); + +    if (directorsEnabled()) { +      // Insert director runtime into the f_runtime file (make it occur before %header section) +      Swig_insert_file("director_common.swg", f_runtime); +      Swig_insert_file("director.swg", f_runtime); +    } +    // Generate the intermediary class +    { +      String *filen = NewStringf("%s%s.java", outputDirectory(imclass_package), imclass_name); +      File *f_im = NewFile(filen, "w", SWIG_output_files()); +      if (!f_im) { +	FileErrorDisplay(filen); +	Exit(EXIT_FAILURE); +      } +      Append(filenames_list, Copy(filen)); +      Delete(filen); +      filen = NULL; + +      // Start writing out the intermediary class file +      emitBanner(f_im); + +      if (imclass_package && package) +        Printf(f_im, "package %s.%s;", package, imclass_package); +      else if (imclass_package) +        Printf(f_im, "package %s;", imclass_package); +      else if (package) +        Printf(f_im, "package %s;\n", package); + +      if (imclass_imports) +	Printf(f_im, "%s\n", imclass_imports); + +      if (Len(imclass_class_modifiers) > 0) +	Printf(f_im, "%s ", imclass_class_modifiers); +      Printf(f_im, "%s ", imclass_name); + +      if (imclass_baseclass && *Char(imclass_baseclass)) +	Printf(f_im, "extends %s ", imclass_baseclass); +      if (Len(imclass_interfaces) > 0) +	Printv(f_im, "implements ", imclass_interfaces, " ", NIL); +      Printf(f_im, "{\n"); + +      // Add the intermediary class methods +      Replaceall(imclass_class_code, "$module", module_class_name); +      Replaceall(imclass_class_code, "$imclassname", imclass_name); +      Printv(f_im, imclass_class_code, NIL); +      Printv(f_im, imclass_cppcasts_code, NIL); +      if (Len(imclass_directors) > 0) +	Printv(f_im, "\n", imclass_directors, NIL); + +      if (n_dmethods > 0) { +	Putc('\n', f_im); +	Printf(f_im, "  private final static native void swig_module_init();\n"); +	Printf(f_im, "  static {\n"); +	Printf(f_im, "    swig_module_init();\n"); +	Printf(f_im, "  }\n"); +      } +      // Finish off the class +      Printf(f_im, "}\n"); +      Delete(f_im); +    } + +    // Generate the Java module class +    { +      String *filen = NewStringf("%s%s.java", SWIG_output_directory(), module_class_name); +      File *f_module = NewFile(filen, "w", SWIG_output_files()); +      if (!f_module) { +	FileErrorDisplay(filen); +	Exit(EXIT_FAILURE); +      } +      Append(filenames_list, Copy(filen)); +      Delete(filen); +      filen = NULL; + +      // Start writing out the module class file +      emitBanner(f_module); + +      if (package) +	Printf(f_module, "package %s;\n", package); + +      if (module_imports) +	Printf(f_module, "%s\n", module_imports); + +      if (doxygen && doxygenTranslator->hasDocumentation(n)) { +	String *doxygen_comments = doxygenTranslator->getDocumentation(n, 0); +	if (comment_creation_chatter) +	  Printf(f_module, "/* This was generated from top() */\n"); +	Printv(f_module, Char(doxygen_comments), NIL); +	Delete(doxygen_comments); +      } +      if (Len(module_class_modifiers) > 0) +	Printf(f_module, "%s ", module_class_modifiers); +      Printf(f_module, "%s ", module_class_name); + +      if (module_baseclass && *Char(module_baseclass)) +	Printf(f_module, "extends %s ", module_baseclass); +      if (Len(module_interfaces) > 0) { +	if (Len(module_class_constants_code) != 0) +	  Printv(f_module, "implements ", constants_interface_name, ", ", module_interfaces, " ", NIL); +	else +	  Printv(f_module, "implements ", module_interfaces, " ", NIL); +      } else { +	if (Len(module_class_constants_code) != 0) +	  Printv(f_module, "implements ", constants_interface_name, " ", NIL); +      } +      Printf(f_module, "{\n"); + +      Replaceall(module_class_code, "$module", module_class_name); +      Replaceall(module_class_constants_code, "$module", module_class_name); + +      Replaceall(module_class_code, "$imclassname", imclass_name); +      Replaceall(module_class_constants_code, "$imclassname", imclass_name); + +      // Add the wrapper methods +      Printv(f_module, module_class_code, NIL); + +      // Finish off the class +      Printf(f_module, "}\n"); +      Delete(f_module); +    } + +    // Generate the Java constants interface +    if (Len(module_class_constants_code) != 0) { +      String *filen = NewStringf("%s%s.java", SWIG_output_directory(), constants_interface_name); +      File *f_module = NewFile(filen, "w", SWIG_output_files()); +      if (!f_module) { +	FileErrorDisplay(filen); +	Exit(EXIT_FAILURE); +      } +      Append(filenames_list, Copy(filen)); +      Delete(filen); +      filen = NULL; + +      // Start writing out the Java constants interface file +      emitBanner(f_module); + +      if (package) +	Printf(f_module, "package %s;\n", package); + +      if (module_imports) +	Printf(f_module, "%s\n", module_imports); + +      Printf(f_module, "public interface %s {\n", constants_interface_name); + +      // Write out all the global constants +      Printv(f_module, module_class_constants_code, NIL); + +      // Finish off the Java interface +      Printf(f_module, "}\n"); +      Delete(f_module); +    } + +    if (upcasts_code) +      Printv(f_wrappers, upcasts_code, NIL); + +    emitDirectorUpcalls(); + +    Printf(f_wrappers, "#ifdef __cplusplus\n"); +    Printf(f_wrappers, "}\n"); +    Printf(f_wrappers, "#endif\n"); + +    // Output a Java type wrapper class for each SWIG type +    for (Iterator swig_type = First(swig_types_hash); swig_type.key; swig_type = Next(swig_type)) { +      emitTypeWrapperClass(swig_type.key, swig_type.item); +    } + +    // Check for overwriting file problems on filesystems that are case insensitive +    Iterator it1; +    Iterator it2; +    for (it1 = First(filenames_list); it1.item; it1 = Next(it1)) { +      String *item1_lower = Swig_string_lower(it1.item); +      for (it2 = Next(it1); it2.item; it2 = Next(it2)) { +	String *item2_lower = Swig_string_lower(it2.item); +	if (it1.item && it2.item) { +	  if (Strcmp(item1_lower, item2_lower) == 0) { +	    Swig_warning(WARN_LANG_PORTABILITY_FILENAME, input_file, line_number, +			 "Portability warning: File %s will be overwritten by %s on case insensitive filesystems such as " +			 "Windows' FAT32 and NTFS unless the class/module name is renamed\n", it1.item, it2.item); +	  } +	} +	Delete(item2_lower); +      } +      Delete(item1_lower); +    } + +    Delete(swig_types_hash); +    swig_types_hash = NULL; +    Delete(filenames_list); +    filenames_list = NULL; +    Delete(imclass_name); +    imclass_name = NULL; +    Delete(imclass_class_code); +    imclass_class_code = NULL; +    Delete(proxy_class_def); +    proxy_class_def = NULL; +    Delete(proxy_class_code); +    proxy_class_code = NULL; +    Delete(module_class_constants_code); +    module_class_constants_code = NULL; +    Delete(imclass_baseclass); +    imclass_baseclass = NULL; +    Delete(imclass_package); +    imclass_package = NULL; +    Delete(imclass_interfaces); +    imclass_interfaces = NULL; +    Delete(imclass_class_modifiers); +    imclass_class_modifiers = NULL; +    Delete(module_class_name); +    module_class_name = NULL; +    Delete(constants_interface_name); +    constants_interface_name = NULL; +    Delete(module_class_code); +    module_class_code = NULL; +    Delete(module_baseclass); +    module_baseclass = NULL; +    Delete(module_interfaces); +    module_interfaces = NULL; +    Delete(module_imports); +    module_imports = NULL; +    Delete(module_class_modifiers); +    module_class_modifiers = NULL; +    Delete(imclass_imports); +    imclass_imports = NULL; +    Delete(imclass_cppcasts_code); +    imclass_cppcasts_code = NULL; +    Delete(imclass_directors); +    imclass_directors = NULL; +    Delete(upcasts_code); +    upcasts_code = NULL; +    Delete(package); +    package = NULL; +    Delete(jnipackage); +    jnipackage = NULL; +    Delete(package_path); +    package_path = NULL; +    Delete(dmethods_seq); +    dmethods_seq = NULL; +    Delete(dmethods_table); +    dmethods_table = NULL; +    n_dmethods = 0; + +    /* Close all of the files */ +    Dump(f_header, f_runtime); + +    if (directorsEnabled()) { +      Dump(f_directors, f_runtime); +      Dump(f_directors_h, f_runtime_h); + +      Printf(f_runtime_h, "\n"); +      Printf(f_runtime_h, "#endif\n"); + +      Delete(f_runtime_h); +      f_runtime_h = NULL; +      Delete(f_directors); +      f_directors = NULL; +      Delete(f_directors_h); +      f_directors_h = NULL; +    } + +    Dump(f_wrappers, f_runtime); +    Wrapper_pretty_print(f_init, f_runtime); +    Delete(f_header); +    Delete(f_wrappers); +    Delete(f_init); +    Dump(f_runtime, f_begin); +    Delete(f_runtime); +    Delete(f_begin); +    return SWIG_OK; +  } + +  /* ----------------------------------------------------------------------------- +   * emitBanner() +   * ----------------------------------------------------------------------------- */ + +  void emitBanner(File *f) { +    Printf(f, "/* ----------------------------------------------------------------------------\n"); +    Swig_banner_target_lang(f, " *"); +    Printf(f, " * ----------------------------------------------------------------------------- */\n\n"); +  } + +  /*----------------------------------------------------------------------- +   * Add new director upcall signature +   *----------------------------------------------------------------------*/ + +  UpcallData *addUpcallMethod(String *imclass_method, String *class_method, String *imclass_desc, String *class_desc, String *decl) { +    String *key = NewStringf("%s|%s", imclass_method, decl); + +    ++curr_class_dmethod; + +    String *imclass_methodidx = NewStringf("%d", n_dmethods); +    String *class_methodidx = NewStringf("%d", n_dmethods - first_class_dmethod); +    n_dmethods++; + +    Hash *new_udata = NewHash(); +    Append(dmethods_seq, new_udata); +    Setattr(dmethods_table, key, new_udata); + +    Setattr(new_udata, "method", Copy(class_method)); +    Setattr(new_udata, "fdesc", Copy(class_desc)); +    Setattr(new_udata, "imclass_method", Copy(imclass_method)); +    Setattr(new_udata, "imclass_fdesc", Copy(imclass_desc)); +    Setattr(new_udata, "imclass_methodidx", imclass_methodidx); +    Setattr(new_udata, "class_methodidx", class_methodidx); +    Setattr(new_udata, "decl", Copy(decl)); + +    Delete(key); +    return new_udata; +  } + +  /*----------------------------------------------------------------------- +   * Get director upcall signature +   *----------------------------------------------------------------------*/ + +  UpcallData *getUpcallMethodData(String *director_class, String *decl) { +    String *key = NewStringf("%s|%s", director_class, decl); +    UpcallData *udata = Getattr(dmethods_table, key); + +    Delete(key); +    return udata; +  } + +  /* ---------------------------------------------------------------------- +   * nativeWrapper() +   * ---------------------------------------------------------------------- */ + +  virtual int nativeWrapper(Node *n) { +    String *wrapname = Getattr(n, "wrap:name"); + +    if (!addSymbol(wrapname, n, imclass_name)) +      return SWIG_ERROR; + +    if (Getattr(n, "type")) { +      Swig_save("nativeWrapper", n, "name", NIL); +      Setattr(n, "name", wrapname); +      native_function_flag = true; +      functionWrapper(n); +      Swig_restore(n); +      native_function_flag = false; +    } else { +      Swig_error(input_file, line_number, "No return type for %%native method %s.\n", Getattr(n, "wrap:name")); +    } + +    return SWIG_OK; +  } + +  /* ---------------------------------------------------------------------- +   * functionWrapper() +   * ---------------------------------------------------------------------- */ + +  virtual int functionWrapper(Node *n) { +    String *symname = Getattr(n, "sym:name"); +    SwigType *t = Getattr(n, "type"); +    ParmList *l = Getattr(n, "parms"); +    String *tm; +    Parm *p; +    int i; +    String *c_return_type = NewString(""); +    String *im_return_type = NewString(""); +    String *cleanup = NewString(""); +    String *outarg = NewString(""); +    String *body = NewString(""); +    int num_arguments = 0; +    int gencomma = 0; +    bool is_void_return; +    String *overloaded_name = getOverloadedName(n); +    String *nondir_args = NewString(""); +    bool is_destructor = (Cmp(Getattr(n, "nodeType"), "destructor") == 0); + +    if (!Getattr(n, "sym:overloaded")) { +      if (!addSymbol(symname, n, imclass_name)) +	return SWIG_ERROR; +    } + +    /* +       The rest of this function deals with generating the intermediary class wrapper function (that wraps +       a c/c++ function) and generating the JNI c code. Each Java wrapper function has a  +       matching JNI c function call. +     */ + +    // A new wrapper function object +    Wrapper *f = NewWrapper(); + +    // Make a wrapper name for this function +    String *jniname = makeValidJniName(overloaded_name); +    String *wname = Swig_name_wrapper(jniname); + +    Delete(jniname); + +    /* Attach the non-standard typemaps to the parameter list. */ +    Swig_typemap_attach_parms("jni", l, f); +    Swig_typemap_attach_parms("jtype", l, f); +    Swig_typemap_attach_parms("jstype", l, f); + +    /* Get return types */ +    if ((tm = Swig_typemap_lookup("jni", n, "", 0))) { +      Printf(c_return_type, "%s", tm); +    } else { +      Swig_warning(WARN_JAVA_TYPEMAP_JNI_UNDEF, input_file, line_number, "No jni typemap defined for %s\n", SwigType_str(t, 0)); +    } + +    if ((tm = Swig_typemap_lookup("jtype", n, "", 0))) { +      Printf(im_return_type, "%s", tm); +    } else { +      Swig_warning(WARN_JAVA_TYPEMAP_JTYPE_UNDEF, input_file, line_number, "No jtype typemap defined for %s\n", SwigType_str(t, 0)); +    } + +    is_void_return = (Cmp(c_return_type, "void") == 0); +    if (!is_void_return) +      Wrapper_add_localv(f, "jresult", c_return_type, "jresult = 0", NIL); + +    Printv(f->def, "SWIGEXPORT ", c_return_type, " JNICALL ", wname, "(JNIEnv *jenv, jclass jcls", NIL); + +    // Usually these function parameters are unused - The code below ensures +    // that compilers do not issue such a warning if configured to do so. + +    Printv(f->code, "    (void)jenv;\n", NIL); +    Printv(f->code, "    (void)jcls;\n", NIL); + +    // Emit all of the local variables for holding arguments. +    emit_parameter_variables(l, f); + +    /* Attach the standard typemaps */ +    emit_attach_parmmaps(l, f); + +    // Parameter overloading +    Setattr(n, "wrap:parms", l); +    Setattr(n, "wrap:name", wname); + +    // Wrappers not wanted for some methods where the parameters cannot be overloaded in Java +    if (Getattr(n, "sym:overloaded")) { +      // Emit warnings for the few cases that can't be overloaded in Java and give up on generating wrapper +      Swig_overload_check(n); +      if (Getattr(n, "overload:ignore")) { +	DelWrapper(f); +	return SWIG_OK; +      } +    } + +    Printf(imclass_class_code, "  public final static native %s %s(", im_return_type, overloaded_name); + +    num_arguments = emit_num_arguments(l); + +    // Now walk the function parameter list and generate code to get arguments +    for (i = 0, p = l; i < num_arguments; i++) { + +      while (checkAttribute(p, "tmap:in:numinputs", "0")) { +	p = Getattr(p, "tmap:in:next"); +      } + +      SwigType *pt = Getattr(p, "type"); +      String *ln = Getattr(p, "lname"); +      String *im_param_type = NewString(""); +      String *c_param_type = NewString(""); +      String *arg = NewString(""); + +      Printf(arg, "j%s", ln); + +      /* Get the JNI C types of the parameter */ +      if ((tm = Getattr(p, "tmap:jni"))) { +	Printv(c_param_type, tm, NIL); +      } else { +	Swig_warning(WARN_JAVA_TYPEMAP_JNI_UNDEF, input_file, line_number, "No jni typemap defined for %s\n", SwigType_str(pt, 0)); +      } + +      /* Get the intermediary class parameter types of the parameter */ +      if ((tm = Getattr(p, "tmap:jtype"))) { +	Printv(im_param_type, tm, NIL); +      } else { +	Swig_warning(WARN_JAVA_TYPEMAP_JTYPE_UNDEF, input_file, line_number, "No jtype typemap defined for %s\n", SwigType_str(pt, 0)); +      } + +      /* Add parameter to intermediary class method */ +      if (gencomma) +	Printf(imclass_class_code, ", "); +      Printf(imclass_class_code, "%s %s", im_param_type, arg); + +      // Add parameter to C function +      Printv(f->def, ", ", c_param_type, " ", arg, NIL); + +      ++gencomma; + +      // Premature garbage collection prevention parameter +      if (!is_destructor) { +	String *pgc_parameter = prematureGarbageCollectionPreventionParameter(pt, p); +	if (pgc_parameter) { +	  Printf(imclass_class_code, ", %s %s_", pgc_parameter, arg); +	  Printf(f->def, ", jobject %s_", arg); +	  Printf(f->code, "    (void)%s_;\n", arg); +	} +      } +      // Get typemap for this argument +      if ((tm = Getattr(p, "tmap:in"))) { +	addThrows(n, "tmap:in", p); +	Replaceall(tm, "$arg", arg);	/* deprecated? */ +	Replaceall(tm, "$input", arg); +	Setattr(p, "emit:input", arg); + +	Printf(nondir_args, "%s\n", tm); + +	p = Getattr(p, "tmap:in:next"); +      } else { +	Swig_warning(WARN_TYPEMAP_IN_UNDEF, input_file, line_number, "Unable to use type %s as a function argument.\n", SwigType_str(pt, 0)); +	p = nextSibling(p); +      } + +      Delete(im_param_type); +      Delete(c_param_type); +      Delete(arg); +    } + +    Printv(f->code, nondir_args, NIL); +    Delete(nondir_args); + +    /* Insert constraint checking code */ +    for (p = l; p;) { +      if ((tm = Getattr(p, "tmap:check"))) { +	addThrows(n, "tmap:check", p); +	Replaceall(tm, "$arg", Getattr(p, "emit:input"));	/* deprecated? */ +	Replaceall(tm, "$input", Getattr(p, "emit:input")); +	Printv(f->code, tm, "\n", NIL); +	p = Getattr(p, "tmap:check:next"); +      } else { +	p = nextSibling(p); +      } +    } + +    /* Insert cleanup code */ +    for (p = l; p;) { +      if ((tm = Getattr(p, "tmap:freearg"))) { +	addThrows(n, "tmap:freearg", p); +	Replaceall(tm, "$arg", Getattr(p, "emit:input"));	/* deprecated? */ +	Replaceall(tm, "$input", Getattr(p, "emit:input")); +	Printv(cleanup, tm, "\n", NIL); +	p = Getattr(p, "tmap:freearg:next"); +      } else { +	p = nextSibling(p); +      } +    } + +    /* Insert argument output code */ +    for (p = l; p;) { +      if ((tm = Getattr(p, "tmap:argout"))) { +	addThrows(n, "tmap:argout", p); +	Replaceall(tm, "$arg", Getattr(p, "emit:input"));	/* deprecated? */ +	Replaceall(tm, "$result", "jresult"); +	Replaceall(tm, "$input", Getattr(p, "emit:input")); +	Printv(outarg, tm, "\n", NIL); +	p = Getattr(p, "tmap:argout:next"); +      } else { +	p = nextSibling(p); +      } +    } + +    // Get any Java exception classes in the throws typemap +    ParmList *throw_parm_list = NULL; +    if ((throw_parm_list = Getattr(n, "catchlist"))) { +      Swig_typemap_attach_parms("throws", throw_parm_list, f); +      for (p = throw_parm_list; p; p = nextSibling(p)) { +	if (Getattr(p, "tmap:throws")) { +	  addThrows(n, "tmap:throws", p); +	} +      } +    } + +    // Now write code to make the function call +    if (!native_function_flag) { + +      Swig_director_emit_dynamic_cast(n, f); +      String *actioncode = emit_action(n); + +      // Handle exception classes specified in the "except" feature's "throws" attribute +      addThrows(n, "feature:except", n); + +      /* Return value if necessary  */ +      if ((tm = Swig_typemap_lookup_out("out", n, Swig_cresult_name(), f, actioncode))) { +	addThrows(n, "tmap:out", n); +	Replaceall(tm, "$result", "jresult"); + +        if (GetFlag(n, "feature:new")) +          Replaceall(tm, "$owner", "1"); +        else +          Replaceall(tm, "$owner", "0"); + +	Printf(f->code, "%s", tm); +	if (Len(tm)) +	  Printf(f->code, "\n"); +      } else { +	Swig_warning(WARN_TYPEMAP_OUT_UNDEF, input_file, line_number, "Unable to use return type %s in function %s.\n", SwigType_str(t, 0), Getattr(n, "name")); +      } +      emit_return_variable(n, t, f); +    } + +    /* Output argument output code */ +    Printv(f->code, outarg, NIL); + +    /* Output cleanup code */ +    Printv(f->code, cleanup, NIL); + +    /* Look to see if there is any newfree cleanup code */ +    if (GetFlag(n, "feature:new")) { +      if ((tm = Swig_typemap_lookup("newfree", n, Swig_cresult_name(), 0))) { +	addThrows(n, "tmap:newfree", n); +	Printf(f->code, "%s\n", tm); +      } +    } + +    /* See if there is any return cleanup code */ +    if (!native_function_flag) { +      if ((tm = Swig_typemap_lookup("ret", n, Swig_cresult_name(), 0))) { +	addThrows(n, "tmap:ret", n); +	Printf(f->code, "%s\n", tm); +      } +    } + +    /* Finish C function and intermediary class function definitions */ +    Printf(imclass_class_code, ")"); +    generateThrowsClause(n, imclass_class_code); +    Printf(imclass_class_code, ";\n"); + +    Printf(f->def, ") {"); + +    if (!is_void_return) +      Printv(f->code, "    return jresult;\n", NIL); +    Printf(f->code, "}\n"); + +    /* Substitute the cleanup code */ +    Replaceall(f->code, "$cleanup", cleanup); + +    /* Substitute the function name */ +    Replaceall(f->code, "$symname", symname); + +    /* Contract macro modification */ +    Replaceall(f->code, "SWIG_contract_assert(", "SWIG_contract_assert($null, "); + +    if (!is_void_return) +      Replaceall(f->code, "$null", "0"); +    else +      Replaceall(f->code, "$null", ""); + +    /* Dump the function out */ +    if (!native_function_flag) +      Wrapper_print(f, f_wrappers); + +    if (!(proxy_flag && is_wrapping_class()) && !enum_constant_flag) { +      moduleClassFunctionHandler(n); +    } + +    /*  +     * Generate the proxy class getters/setters for public member variables. +     * Not for enums and constants. +     */ +    if (proxy_flag && wrapping_member_flag && !enum_constant_flag) { +      // Capitalize the first letter in the variable to create a JavaBean type getter/setter function name +      bool getter_flag = Cmp(symname, Swig_name_set(getNSpace(), Swig_name_member(0, getClassPrefix(), variable_name))) != 0; + +      String *getter_setter_name = NewString(""); +      if (!getter_flag) +	Printf(getter_setter_name, "set"); +      else +	Printf(getter_setter_name, "get"); +      Putc(toupper((int) *Char(variable_name)), getter_setter_name); +      Printf(getter_setter_name, "%s", Char(variable_name) + 1); + +      Setattr(n, "proxyfuncname", getter_setter_name); +      Setattr(n, "imfuncname", symname); + +      proxyClassFunctionHandler(n); +      Delete(getter_setter_name); +    } + +    Delete(c_return_type); +    Delete(im_return_type); +    Delete(cleanup); +    Delete(outarg); +    Delete(body); +    Delete(overloaded_name); +    DelWrapper(f); +    return SWIG_OK; +  } + +  /* ----------------------------------------------------------------------- +   * variableWrapper() +   * ----------------------------------------------------------------------- */ + +  virtual int variableWrapper(Node *n) { +    variable_wrapper_flag = true; +    Language::variableWrapper(n);	/* Default to functions */ +    variable_wrapper_flag = false; +    return SWIG_OK; +  } + +  /* ----------------------------------------------------------------------- +   * globalvariableHandler() +   * ------------------------------------------------------------------------ */ + +  virtual int globalvariableHandler(Node *n) { + +    variable_name = Getattr(n, "sym:name"); +    global_variable_flag = true; +    int ret = Language::globalvariableHandler(n); +    global_variable_flag = false; +    return ret; +  } + +  String *getCurrentScopeName(String *nspace) { +    String *scope = 0; +    if (nspace || getCurrentClass()) { +      scope = NewString(""); +      if (nspace) +	Printf(scope, "%s", nspace); +      if (Node* cls = getCurrentClass()) { +	if (Node *outer = Getattr(cls, "nested:outer")) { +	  String *outerClassesPrefix = Copy(Getattr(outer, "sym:name")); +	  for (outer = Getattr(outer, "nested:outer"); outer != 0; outer = Getattr(outer, "nested:outer")) { +	    Push(outerClassesPrefix, "."); +	    Push(outerClassesPrefix, Getattr(outer, "sym:name")); +	  } +	  Printv(scope, nspace ? "." : "", outerClassesPrefix, ".", proxy_class_name, NIL); +	  Delete(outerClassesPrefix); +	} else +	  Printv(scope, nspace ? "." : "", proxy_class_name, NIL); +      } +    } +    return scope; +  } + +  /* ---------------------------------------------------------------------- +   * enumDeclaration() +   * +   * C/C++ enums can be mapped in one of 4 ways, depending on the java:enum feature specified: +   * 1) Simple enums - simple constant within the proxy class or module class +   * 2) Typeunsafe enums - simple constant in a Java class (class named after the c++ enum name) +   * 3) Typesafe enum - typesafe enum pattern (class named after the c++ enum name) +   * 4) Proper enums - proper Java enum +   * Anonymous enums always default to 1) +   * ---------------------------------------------------------------------- */ + +  virtual int enumDeclaration(Node *n) { + +    if (!ImportMode) { +      if (getCurrentClass() && (cplus_mode != PUBLIC)) +	return SWIG_NOWRAP; + +      String *nspace = Getattr(n, "sym:nspace"); // NSpace/getNSpace() only works during Language::enumDeclaration call +      if (proxy_flag && !is_wrapping_class()) { +	// Global enums / enums in a namespace +	assert(!full_imclass_name); +	constructIntermediateClassName(n); +      } + +      enum_code = NewString(""); +      String *symname = Getattr(n, "sym:name"); +      String *constants_code = (proxy_flag && is_wrapping_class())? proxy_class_constants_code : module_class_constants_code; +      EnumFeature enum_feature = decodeEnumFeature(n); +      String *typemap_lookup_type = Getattr(n, "name"); + +      if ((enum_feature != SimpleEnum) && symname && typemap_lookup_type) { +	// Wrap (non-anonymous) C/C++ enum within a typesafe, typeunsafe or proper Java enum + +	if (doxygen && doxygenTranslator->hasDocumentation(n)) { +	  String *doxygen_comments = doxygenTranslator->getDocumentation(n, 0); +	  if (comment_creation_chatter) +	    Printf(enum_code, "/* This was generated from enumDeclaration() */\n"); +	  Printv(enum_code, Char(doxygen_comments), NIL); +	  Delete(doxygen_comments); +	} + +	String *scope = getCurrentScopeName(nspace); +	if (!addSymbol(symname, n, scope)) +	  return SWIG_ERROR; + +	// Pure Java baseclass and interfaces +	const String *pure_baseclass = typemapLookup(n, "javabase", typemap_lookup_type, WARN_NONE); +	const String *pure_interfaces = typemapLookup(n, "javainterfaces", typemap_lookup_type, WARN_NONE); + +	// Emit the enum +	Printv(enum_code, typemapLookup(n, "javaclassmodifiers", typemap_lookup_type, WARN_JAVA_TYPEMAP_CLASSMOD_UNDEF),	// Class modifiers (enum modifiers really) +	       " ", symname, *Char(pure_baseclass) ?	// Bases +	       " extends " : "", pure_baseclass, *Char(pure_interfaces) ?	// Interfaces +	       " implements " : "", pure_interfaces, " {\n", NIL); +	if (proxy_flag && is_wrapping_class()) +	  Replaceall(enum_code, "$static ", "static "); +	else +	  Replaceall(enum_code, "$static ", ""); +	Delete(scope); +      } else { +	if (symname && !Getattr(n, "unnamedinstance")) +	  Printf(constants_code, "  // %s \n", symname); +	// Translate and write javadoc comment for the enum itself if flagged +	if (doxygen && doxygenTranslator->hasDocumentation(n)) { +	  String *doxygen_comments = doxygenTranslator->getDocumentation(n, "  "); +	  if (comment_creation_chatter) +	    Printf(constants_code, "/* This was generated from enumDeclaration() */\n"); +	  Printf(constants_code, Char(doxygen_comments)); +	  Printf(constants_code, "\n"); +	  Delete(doxygen_comments); +	} +      } + +      // Emit each enum item +      Language::enumDeclaration(n); + +      if ((enum_feature != SimpleEnum) && symname && typemap_lookup_type) { +	// Wrap (non-anonymous) C/C++ enum within a typesafe, typeunsafe or proper Java enum +	// Finish the enum declaration +	// Typemaps are used to generate the enum definition in a similar manner to proxy classes. +	Printv(enum_code, (enum_feature == ProperEnum) ? ";\n" : "", typemapLookup(n, "javabody", typemap_lookup_type, WARN_JAVA_TYPEMAP_JAVABODY_UNDEF),	// main body of class +	       typemapLookup(n, "javacode", typemap_lookup_type, WARN_NONE),	// extra Java code +	       "}", NIL); + +	Replaceall(enum_code, "$javaclassname", symname); + +	// Substitute $enumvalues - intended usage is for typesafe enums +	if (Getattr(n, "enumvalues")) +	  Replaceall(enum_code, "$enumvalues", Getattr(n, "enumvalues")); +	else +	  Replaceall(enum_code, "$enumvalues", ""); + +	if (proxy_flag && is_wrapping_class()) { +	  // Enums defined within the C++ class are defined within the proxy class + +	  // Add extra indentation +	  Replaceall(enum_code, "\n", "\n  "); +	  Replaceall(enum_code, "  \n", "\n"); +	  Printv(proxy_class_constants_code, "  ", enum_code, "\n\n", NIL); +	} else { +	  // Global enums are defined in their own file +	  String *output_directory = outputDirectory(nspace); +	  String *filen = NewStringf("%s%s.java", output_directory, symname); +	  File *f_enum = NewFile(filen, "w", SWIG_output_files()); +	  if (!f_enum) { +	    FileErrorDisplay(filen); +	    Exit(EXIT_FAILURE); +	  } +	  Append(filenames_list, Copy(filen)); +	  Delete(filen); +	  filen = NULL; + +	  // Start writing out the enum file +	  emitBanner(f_enum); + +	  if (package || nspace) { +	    Printf(f_enum, "package "); +	    if (package) +	      Printv(f_enum, package, nspace ? "." : "", NIL); +	    if (nspace) +	      Printv(f_enum, nspace, NIL); +	    Printf(f_enum, ";\n"); +	  } + +	  Printv(f_enum, typemapLookup(n, "javaimports", typemap_lookup_type, WARN_NONE), // Import statements +		 "\n", enum_code, "\n", NIL); + +	  Printf(f_enum, "\n"); +	  Delete(f_enum); +	  Delete(output_directory); +	} +      } else { +	// Wrap C++ enum with simple constant +	Printf(enum_code, "\n"); +	if (proxy_flag && is_wrapping_class()) +	  Printv(proxy_class_constants_code, enum_code, NIL); +	else +	  Printv(module_class_constants_code, enum_code, NIL); +      } + +      Delete(enum_code); +      enum_code = NULL; + +      if (proxy_flag && !is_wrapping_class()) { +	Delete(full_imclass_name); +	full_imclass_name = 0; +      } +    } +    return SWIG_OK; +  } + +  /* ---------------------------------------------------------------------- +   * enumvalueDeclaration() +   * ---------------------------------------------------------------------- */ + +  virtual int enumvalueDeclaration(Node *n) { +    if (getCurrentClass() && (cplus_mode != PUBLIC)) +      return SWIG_NOWRAP; + +    Swig_require("enumvalueDeclaration", n, "*name", "?value", NIL); +    String *symname = Getattr(n, "sym:name"); +    String *value = Getattr(n, "value"); +    String *name = Getattr(n, "name"); +    Node *parent = parentNode(n); +    int unnamedinstance = GetFlag(parent, "unnamedinstance"); +    String *parent_name = Getattr(parent, "name"); +    String *nspace = getNSpace(); +    String *newsymname = 0; +    String *tmpValue; + +    // Strange hack from parent method +    if (value) +      tmpValue = NewString(value); +    else +      tmpValue = NewString(name); +    // Note that this is used in enumValue() amongst other places +    Setattr(n, "value", tmpValue); + +    // Deal with enum values that are not int +    int swigtype = SwigType_type(Getattr(n, "type")); +    if (swigtype == T_BOOL) { +      const char *val = Equal(Getattr(n, "enumvalue"), "true") ? "1" : "0"; +      Setattr(n, "enumvalue", val); +    } else if (swigtype == T_CHAR) { +      String *val = NewStringf("'%(escape)s'", Getattr(n, "enumvalue")); +      Setattr(n, "enumvalue", val); +      Delete(val); +    } + +    { +      EnumFeature enum_feature = decodeEnumFeature(parent); + +      if ((enum_feature == SimpleEnum) && GetFlag(parent, "scopedenum")) { +	newsymname = Swig_name_member(0, Getattr(parent, "sym:name"), symname); +	symname = newsymname; +      } + +      // Add to language symbol table +      String *scope = 0; +      if (unnamedinstance || !parent_name || enum_feature == SimpleEnum) { +	String *enumClassPrefix = getEnumClassPrefix(); +	if (enumClassPrefix) { +	  scope = NewString(""); +	  if (nspace) +	    Printf(scope, "%s.", nspace); +	  Printf(scope, "%s", enumClassPrefix); +	} else { +	  scope = Copy(constants_interface_name); +	} +      } else { +	scope = getCurrentScopeName(nspace); +	if (!scope) +	  scope = Copy(Getattr(parent, "sym:name")); +	else +	  Printf(scope, ".%s", Getattr(parent, "sym:name")); +      } +      if (!addSymbol(symname, n, scope)) +	return SWIG_ERROR; +       +      if ((enum_feature == ProperEnum) && parent_name && !unnamedinstance) { +	if (!GetFlag(n, "firstenumitem")) +	  Printf(enum_code, ",\n"); +      } + +      // Translate and write javadoc comment if flagged +      if (doxygen && doxygenTranslator->hasDocumentation(n)) { +	String *doxygen_comments = doxygenTranslator->getDocumentation(n, "  "); +	if (comment_creation_chatter) +	  Printf(enum_code, "/* This was generated from enumvalueDeclaration() */\n"); +	Printv(enum_code, Char(doxygen_comments), NIL); +	Delete(doxygen_comments); +      } + +      if ((enum_feature == ProperEnum) && parent_name && !unnamedinstance) { +	// Wrap (non-anonymous) C/C++ enum with a proper Java enum +	// Emit the enum item. +	Printf(enum_code, "  %s", symname); +	if (Getattr(n, "enumvalue")) { +	  String *value = enumValue(n); +	  Printf(enum_code, "(%s)", value); +	  Delete(value); +	} +      } else { +	// Wrap C/C++ enums with constant integers or use the typesafe enum pattern +	SwigType *typemap_lookup_type = parent_name ? parent_name : NewString("enum "); +	Setattr(n, "type", typemap_lookup_type); +	const String *tm = typemapLookup(n, "jstype", typemap_lookup_type, WARN_JAVA_TYPEMAP_JSTYPE_UNDEF); + +	String *return_type = Copy(tm); +	substituteClassname(typemap_lookup_type, return_type); +        const String *methodmods = Getattr(n, "feature:java:methodmodifiers"); +        methodmods = methodmods ? methodmods : (is_public(n) ? public_string : protected_string); + +	if ((enum_feature == TypesafeEnum) && parent_name && !unnamedinstance) { +	  // Wrap (non-anonymous) enum using the typesafe enum pattern +	  if (Getattr(n, "enumvalue")) { +	    String *value = enumValue(n); +	    Printf(enum_code, "  %s final static %s %s = new %s(\"%s\", %s);\n", methodmods, return_type, symname, return_type, symname, value); +	    Delete(value); +	  } else { +	    Printf(enum_code, "  %s final static %s %s = new %s(\"%s\");\n", methodmods, return_type, symname, return_type, symname); +	  } +	} else { +	  // Simple integer constants +	  // Note these are always generated for anonymous enums, no matter what enum_feature is specified +	  // Code generated is the same for SimpleEnum and TypeunsafeEnum -> the class it is generated into is determined later +	  String *value = enumValue(n); +	  Printf(enum_code, "  %s final static %s %s = %s;\n", methodmods, return_type, symname, value); +	  Delete(value); +	} +	Delete(return_type); +      } + +      // Add the enum value to the comma separated list being constructed in the enum declaration. +      String *enumvalues = Getattr(parent, "enumvalues"); +      if (!enumvalues) +	Setattr(parent, "enumvalues", Copy(symname)); +      else +	Printv(enumvalues, ", ", symname, NIL); +      Delete(scope); +    } + +    Delete(newsymname); +    Delete(tmpValue); +    Swig_restore(n); +    return SWIG_OK; +  } + +  /* ----------------------------------------------------------------------- +   * constantWrapper() +   * Used for wrapping constants - #define or %constant. +   * Also for inline initialised const static primitive type member variables (short, int, double, enums etc). +   * Java static final variables are generated for these. +   * If the %javaconst(1) feature is used then the C constant value is used to initialise the Java final variable. +   * If not, a JNI method is generated to get the C constant value for initialisation of the Java final variable. +   * However, if the %javaconstvalue feature is used, it overrides all other ways to generate the initialisation. +   * Also note that this method might be called for wrapping enum items (when the enum is using %javaconst(0)). +   * ------------------------------------------------------------------------ */ + +  virtual int constantWrapper(Node *n) { +    String *symname = Getattr(n, "sym:name"); +    SwigType *t = Getattr(n, "type"); +    SwigType *valuetype = Getattr(n, "valuetype"); +    ParmList *l = Getattr(n, "parms"); +    String *tm; +    String *return_type = NewString(""); +    String *constants_code = NewString(""); +    Swig_save("constantWrapper", n, "value", NIL); + +    // Translate and write javadoc comment if flagged +    if (doxygen && doxygenTranslator->hasDocumentation(n)) { +      String *doxygen_comments = doxygenTranslator->getDocumentation(n, "  "); +      if (comment_creation_chatter) +	Printf(constants_code, "/* This was generated from constantWrapper() */\n"); +      Printv(constants_code, Char(doxygen_comments), NIL); +      Delete(doxygen_comments); +    } +     +    bool is_enum_item = (Cmp(nodeType(n), "enumitem") == 0); + +    const String *itemname = (proxy_flag && wrapping_member_flag) ? variable_name : symname; +    if (!is_enum_item) { +      String *scope = 0; +      if (proxy_class_name) { +	String *nspace = getNSpace(); +	scope = NewString(""); +	if (nspace) +	  Printf(scope, "%s.", nspace); +	Printf(scope, "%s", proxy_class_name); +      } else { +	scope = Copy(constants_interface_name); +      } +      if (!addSymbol(itemname, n, scope)) +	return SWIG_ERROR; +      Delete(scope); +    } + +    // The %javaconst feature determines how the constant value is obtained +    int const_feature_flag = GetFlag(n, "feature:java:const"); + +    /* Adjust the enum type for the Swig_typemap_lookup. +     * We want the same jstype typemap for all the enum items so we use the enum type (parent node). */ +    if (is_enum_item) { +      t = Getattr(parentNode(n), "enumtype"); +      Setattr(n, "type", t); +    } + +    /* Attach the non-standard typemaps to the parameter list. */ +    Swig_typemap_attach_parms("jstype", l, NULL); + +    /* Get Java return types */ +    bool classname_substituted_flag = false; + +    if ((tm = Swig_typemap_lookup("jstype", n, "", 0))) { +      classname_substituted_flag = substituteClassname(t, tm); +      Printf(return_type, "%s", tm); +    } else { +      Swig_warning(WARN_JAVA_TYPEMAP_JSTYPE_UNDEF, input_file, line_number, "No jstype typemap defined for %s\n", SwigType_str(t, 0)); +    } + +    // Add the stripped quotes back in +    String *new_value = NewString(""); +    if (SwigType_type(t) == T_STRING) { +      Printf(new_value, "\"%s\"", Copy(Getattr(n, "value"))); +      Setattr(n, "value", new_value); +    } else if (SwigType_type(t) == T_CHAR) { +      Printf(new_value, "\'%s\'", Copy(Getattr(n, "value"))); +      Setattr(n, "value", new_value); +    } + +    const String *methodmods = Getattr(n, "feature:java:methodmodifiers"); +    methodmods = methodmods ? methodmods : (is_public(n) ? public_string : protected_string); + +    Printf(constants_code, "  %s final static %s %s = ", methodmods, return_type, itemname); + +    // Check for the %javaconstvalue feature +    String *value = Getattr(n, "feature:java:constvalue"); + +    if (value) { +      Printf(constants_code, "%s;\n", value); +    } else if (!const_feature_flag) { +      // Default enum and constant handling will work with any type of C constant and initialises the Java variable from C through a JNI call. + +      if (classname_substituted_flag) { +	if (SwigType_isenum(t)) { +	  // This handles wrapping of inline initialised const enum static member variables (not when wrapping enum items - ignored later on) +	  Printf(constants_code, "%s.swigToEnum(%s.%s());\n", return_type, full_imclass_name ? full_imclass_name : imclass_name, Swig_name_get(getNSpace(), symname)); +	} else { +	  // This handles function pointers using the %constant directive +	  Printf(constants_code, "new %s(%s.%s(), false);\n", return_type, full_imclass_name ? full_imclass_name : imclass_name, Swig_name_get(getNSpace(), symname)); +	} +      } else { +	Printf(constants_code, "%s.%s();\n", full_imclass_name ? full_imclass_name : imclass_name, Swig_name_get(getNSpace(), symname)); +      } + +      // Each constant and enum value is wrapped with a separate JNI function call +      SetFlag(n, "feature:immutable"); +      enum_constant_flag = true; +      variableWrapper(n); +      enum_constant_flag = false; +    } else { +      // Alternative constant handling will use the C syntax to make a true Java constant and hope that it compiles as Java code +      if (Getattr(n, "wrappedasconstant")) { +	if (SwigType_type(valuetype) == T_CHAR) +          Printf(constants_code, "\'%(escape)s\';\n", Getattr(n, "staticmembervariableHandler:value")); +	else +          Printf(constants_code, "%s;\n", Getattr(n, "staticmembervariableHandler:value")); +      } else { +        Printf(constants_code, "%s;\n", Getattr(n, "value")); +      } +    } + +    // Emit the generated code to appropriate place +    // Enums only emit the intermediate and JNI methods, so no proxy or module class wrapper methods needed +    if (!is_enum_item) { +      if (proxy_flag && wrapping_member_flag) +	Printv(proxy_class_constants_code, constants_code, NIL); +      else +	Printv(module_class_constants_code, constants_code, NIL); +    } +    // Cleanup +    Swig_restore(n); +    Delete(new_value); +    Delete(return_type); +    Delete(constants_code); +    return SWIG_OK; +  } + +  /* ----------------------------------------------------------------------------- +   * insertDirective() +   * ----------------------------------------------------------------------------- */ + +  virtual int insertDirective(Node *n) { +    int ret = SWIG_OK; +    String *code = Getattr(n, "code"); +    String *section = Getattr(n, "section"); +    Replaceall(code, "$module", module_class_name); +    Replaceall(code, "$imclassname", imclass_name); + +    if (!ImportMode && (Cmp(section, "proxycode") == 0)) { +      if (proxy_class_code) { +	Swig_typemap_replace_embedded_typemap(code, n); +	int offset = Len(code) > 0 && *Char(code) == '\n' ? 1 : 0; +	Printv(proxy_class_code, Char(code) + offset, "\n", NIL); +      } +    } else { +      ret = Language::insertDirective(n); +    } +    return ret; +  } + +  /* ----------------------------------------------------------------------------- +   * pragmaDirective() +   * +   * Valid Pragmas: +   * jniclassbase            - base (extends) for the intermediary class +   * jniclasspackage         - package in which to generate the intermediary class +   * jniclassclassmodifiers  - class modifiers for the intermediary class +   * jniclasscode            - text (java code) is copied verbatim to the intermediary class +   * jniclassimports         - import statements for the intermediary class +   * jniclassinterfaces      - interface (implements) for the intermediary class +   * +   * modulebase              - base (extends) for the module class +   * moduleclassmodifiers    - class modifiers for the module class +   * modulecode              - text (java code) is copied verbatim to the module class +   * moduleimports           - import statements for the module class +   * moduleinterfaces        - interface (implements) for the module class +   * +   * ----------------------------------------------------------------------------- */ + +  virtual int pragmaDirective(Node *n) { +    if (!ImportMode) { +      String *lang = Getattr(n, "lang"); +      String *code = Getattr(n, "name"); +      String *value = Getattr(n, "value"); + +      if (Strcmp(lang, "java") == 0) { + +	String *strvalue = NewString(value); +	Replaceall(strvalue, "\\\"", "\""); + +	if (Strcmp(code, "jniclassbase") == 0) { +	  Delete(imclass_baseclass); +	  imclass_baseclass = Copy(strvalue); +	} else if (Strcmp(code, "jniclasspackage") == 0) { +	  Delete(imclass_package); +	  imclass_package = Copy(strvalue); +	  String *imclass_class_package_jniname = makeValidJniName(imclass_package); +	  Printv(jnipackage, imclass_class_package_jniname, NIL); +	  Delete(imclass_class_package_jniname); +	  Replaceall(jnipackage, NSPACE_SEPARATOR, "_"); +	  Append(jnipackage, "_"); + +	  String *wrapper_name = NewString(""); +	  String *imclass_class_jniname = makeValidJniName(imclass_name); +	  Printf(wrapper_name, "Java_%s%s_%%f", jnipackage, imclass_class_jniname); +	  Delete(imclass_class_jniname); + +	  Swig_name_unregister("wrapper"); +	  Swig_name_register("wrapper", Char(wrapper_name)); + +	  Delete(wrapper_name); +	} else if (Strcmp(code, "jniclassclassmodifiers") == 0) { +	  Delete(imclass_class_modifiers); +	  imclass_class_modifiers = Copy(strvalue); +	} else if (Strcmp(code, "jniclasscode") == 0) { +	  Printf(imclass_class_code, "%s\n", strvalue); +	} else if (Strcmp(code, "jniclassimports") == 0) { +	  Delete(imclass_imports); +	  imclass_imports = Copy(strvalue); +	} else if (Strcmp(code, "jniclassinterfaces") == 0) { +	  Delete(imclass_interfaces); +	  imclass_interfaces = Copy(strvalue); +	} else if (Strcmp(code, "modulebase") == 0) { +	  Delete(module_baseclass); +	  module_baseclass = Copy(strvalue); +	} else if (Strcmp(code, "moduleclassmodifiers") == 0) { +	  Delete(module_class_modifiers); +	  module_class_modifiers = Copy(strvalue); +	} else if (Strcmp(code, "modulecode") == 0) { +	  Printf(module_class_code, "%s\n", strvalue); +	} else if (Strcmp(code, "moduleimports") == 0) { +	  Delete(module_imports); +	  module_imports = Copy(strvalue); +	} else if (Strcmp(code, "moduleinterfaces") == 0) { +	  Delete(module_interfaces); +	  module_interfaces = Copy(strvalue); +	} else if (Strcmp(code, "moduleimport") == 0) { +	  Swig_error(input_file, line_number, "Deprecated pragma. Please use the moduleimports pragma.\n"); +	} else if (Strcmp(code, "moduleinterface") == 0) { +	  Swig_error(input_file, line_number, "Deprecated pragma. Please use the moduleinterfaces pragma.\n"); +	} else if (Strcmp(code, "modulemethodmodifiers") == 0) { +	  Swig_error(input_file, line_number, "Deprecated pragma. Please use %%javamethodmodifiers.\n"); +	} else if (Strcmp(code, "allshadowimport") == 0) { +	  Swig_error(input_file, line_number, "Deprecated pragma. Please use %%typemap(javaimports).\n"); +	} else if (Strcmp(code, "allshadowcode") == 0) { +	  Swig_error(input_file, line_number, "Deprecated pragma. Please use %%typemap(javacode).\n"); +	} else if (Strcmp(code, "allshadowbase") == 0) { +	  Swig_error(input_file, line_number, "Deprecated pragma. Please use %%typemap(javabase).\n"); +	} else if (Strcmp(code, "allshadowinterface") == 0) { +	  Swig_error(input_file, line_number, "Deprecated pragma. Please use %%typemap(javainterfaces).\n"); +	} else if (Strcmp(code, "allshadowclassmodifiers") == 0) { +	  Swig_error(input_file, line_number, "Deprecated pragma. Please use %%typemap(javaclassmodifiers).\n"); +	} else if (proxy_flag) { +	  if (Strcmp(code, "shadowcode") == 0) { +	    Swig_error(input_file, line_number, "Deprecated pragma. Please use %%typemap(javacode).\n"); +	  } else if (Strcmp(code, "shadowimport") == 0) { +	    Swig_error(input_file, line_number, "Deprecated pragma. Please use %%typemap(javaimports).\n"); +	  } else if (Strcmp(code, "shadowbase") == 0) { +	    Swig_error(input_file, line_number, "Deprecated pragma. Please use %%typemap(javabase).\n"); +	  } else if (Strcmp(code, "shadowinterface") == 0) { +	    Swig_error(input_file, line_number, "Deprecated pragma. Please use %%typemap(javainterfaces).\n"); +	  } else if (Strcmp(code, "shadowclassmodifiers") == 0) { +	    Swig_error(input_file, line_number, "Deprecated pragma. Please use %%typemap(javaclassmodifiers).\n"); +	  } else { +	    Swig_error(input_file, line_number, "Unrecognized pragma.\n"); +	  } +	} else { +	  Swig_error(input_file, line_number, "Unrecognized pragma.\n"); +	} +	Delete(strvalue); +      } +    } +    return Language::pragmaDirective(n); +  } + +  /* ----------------------------------------------------------------------------- +   * getQualifiedInterfaceName() +   * ----------------------------------------------------------------------------- */ + +  String *getQualifiedInterfaceName(Node *n) { +    String *ret = Getattr(n, "interface:qname"); +    if (!ret) { +      String *nspace = Getattr(n, "sym:nspace"); +      String *symname = Getattr(n, "interface:name"); +      if (nspace) { +	if (package) +	  ret = NewStringf("%s.%s.%s", package, nspace, symname); +	else +	  ret = NewStringf("%s.%s", nspace, symname); +      } else { +	ret = Copy(symname); +      } +      Setattr(n, "interface:qname", ret); +    } +    return ret; +  } + +  /* ----------------------------------------------------------------------------- +   * getInterfaceName() +   * ----------------------------------------------------------------------------- */ + +  String *getInterfaceName(SwigType *t, bool qualified) { +    String *interface_name = NULL; +    if (proxy_flag) { +      Node *n = classLookup(t); +      if (n && Getattr(n, "interface:name")) +	interface_name = qualified ? getQualifiedInterfaceName(n) : Getattr(n, "interface:name"); +    } +    return interface_name; +  } + +  /* ----------------------------------------------------------------------------- +   * addInterfaceNameAndUpcasts() +   * ----------------------------------------------------------------------------- */ + +  void addInterfaceNameAndUpcasts(SwigType *smart, String *interface_list, String *interface_upcasts, List *base_list, SwigType *c_classname) { +    for (Iterator it = First(base_list); it.item; it = Next(it)) { +      Node *base = it.item; +      SwigType *c_baseclassname = Getattr(base, "name"); +      String *interface_name = Getattr(base, "interface:name"); +      if (Len(interface_list)) +	Append(interface_list, ", "); +      Append(interface_list, interface_name); + +      Node *attributes = NewHash(); +      String *interface_code = Copy(typemapLookup(base, "javainterfacecode", Getattr(base, "classtypeobj"), WARN_JAVA_TYPEMAP_INTERFACECODE_UNDEF, attributes)); +      String *cptr_method_name = 0; +      if (interface_code) { +        Replaceall(interface_code, "$interfacename", interface_name); +	Printv(interface_upcasts, interface_code, NIL); +	cptr_method_name = Copy(Getattr(attributes, "tmap:javainterfacecode:cptrmethod")); +      } +      if (!cptr_method_name) +	cptr_method_name = NewStringf("%s_GetInterfaceCPtr", interface_name); +      Replaceall(cptr_method_name, ".", "_"); +      Replaceall(cptr_method_name, "$interfacename", interface_name); + +      String *upcast_method_name = Swig_name_member(getNSpace(), getClassPrefix(), cptr_method_name); +      upcastsCode(smart, upcast_method_name, c_classname, c_baseclassname); + +      Delete(upcast_method_name); +      Delete(cptr_method_name); +      Delete(interface_code); +    } +  } + +  /* ----------------------------------------------------------------------------- +   * upcastsCode() +   * +   * Add code for C++ casting to base class +   * ----------------------------------------------------------------------------- */ + +  void upcastsCode(SwigType *smart, String *upcast_method_name, SwigType *c_classname, SwigType *c_baseclassname) { +    String *jniname = makeValidJniName(upcast_method_name); +    String *wname = Swig_name_wrapper(jniname); + +    Printf(imclass_cppcasts_code, "  public final static native long %s(long jarg1);\n", upcast_method_name); + +    String *classname = SwigType_namestr(c_classname); +    String *baseclassname = SwigType_namestr(c_baseclassname); +    if (smart) { +      String *smartnamestr = SwigType_namestr(smart); +      String *bsmartnamestr = SwigType_namestr(smart); + +      // TODO: SwigType_typedef_resolve_all on a String instead of SwigType is incorrect for templates +      SwigType *rclassname = SwigType_typedef_resolve_all(classname); +      SwigType *rbaseclassname = SwigType_typedef_resolve_all(baseclassname); +      Replaceall(bsmartnamestr, rclassname, rbaseclassname); + +      Printv(upcasts_code, +	  "SWIGEXPORT jlong JNICALL ", wname, "(JNIEnv *jenv, jclass jcls, jlong jarg1) {\n", +	  "    jlong baseptr = 0;\n" +	  "    ", smartnamestr, " *argp1;\n" +	  "    (void)jenv;\n" +	  "    (void)jcls;\n" +	  "    argp1 = *(", smartnamestr, " **)&jarg1;\n" +	  "    *(", bsmartnamestr, " **)&baseptr = argp1 ? new ", bsmartnamestr, "(*argp1) : 0;\n" +	  "    return baseptr;\n" +	  "}\n", "\n", NIL); + +      Delete(rbaseclassname); +      Delete(rclassname); +      Delete(bsmartnamestr); +      Delete(smartnamestr); +    } else { +      Printv(upcasts_code, +	  "SWIGEXPORT jlong JNICALL ", wname, "(JNIEnv *jenv, jclass jcls, jlong jarg1) {\n", +	  "    jlong baseptr = 0;\n" +	  "    (void)jenv;\n" +	  "    (void)jcls;\n" +	  "    *(", baseclassname, " **)&baseptr = *(", classname, " **)&jarg1;\n" +	  "    return baseptr;\n" +	  "}\n", "\n", NIL); +    } + +    Delete(baseclassname); +    Delete(classname); +    Delete(wname); +    Delete(jniname); +  } + +  /* ----------------------------------------------------------------------------- +   * emitProxyClassDefAndCPPCasts() +   * ----------------------------------------------------------------------------- */ + +  void emitProxyClassDefAndCPPCasts(Node *n) { +    SwigType *c_classname = Getattr(n, "name"); +    SwigType *c_baseclassname = NULL; +    String *baseclass = NULL; +    String *interface_list = NewStringEmpty(); +    String *interface_upcasts = NewStringEmpty(); +    SwigType *typemap_lookup_type = Getattr(n, "classtypeobj"); +    bool feature_director = Swig_directorclass(n) ? true : false; +    bool has_outerclass = Getattr(n, "nested:outer") != 0 && !GetFlag(n, "feature:flatnested"); +    SwigType *smart = Swig_cparse_smartptr(n); + +    // Inheritance from pure Java classes +    Node *attributes = NewHash(); +    const String *pure_baseclass = typemapLookup(n, "javabase", typemap_lookup_type, WARN_NONE, attributes); +    bool purebase_replace = GetFlag(attributes, "tmap:javabase:replace") ? true : false; +    bool purebase_notderived = GetFlag(attributes, "tmap:javabase:notderived") ? true : false; +    Delete(attributes); + +    // C++ inheritance +    if (!purebase_replace) { +      List *baselist = Getattr(n, "bases"); +      if (baselist) { +	Iterator base = First(baselist); +	while (base.item) { +	  if (!(GetFlag(base.item, "feature:ignore") || GetFlag(base.item, "feature:interface"))) { +	    SwigType *baseclassname = Getattr(base.item, "name"); +	    if (!c_baseclassname) { +	      String *name = getProxyName(baseclassname); +	      if (name) { +		c_baseclassname = baseclassname; +		baseclass = name; +	      } +	    } else { +	      /* Warn about multiple inheritance for additional base class(es) */ +	      String *proxyclassname = Getattr(n, "classtypeobj"); +	      Swig_warning(WARN_JAVA_MULTIPLE_INHERITANCE, Getfile(n), Getline(n), +		  "Warning for %s, base %s ignored. Multiple inheritance is not supported in Java.\n", SwigType_namestr(proxyclassname), SwigType_namestr(baseclassname)); +	    } +	  } +	  base = Next(base); +	} +      } +    } + +    List *interface_bases = Getattr(n, "interface:bases"); +    if (interface_bases) +      addInterfaceNameAndUpcasts(smart, interface_list, interface_upcasts, interface_bases, c_classname); + +    bool derived = baseclass != 0; +    if (derived && purebase_notderived) +      pure_baseclass = empty_string; +    const String *wanted_base = baseclass ? baseclass : pure_baseclass; + +    if (purebase_replace) { +      wanted_base = pure_baseclass; +      derived = false; +      baseclass = NULL; +      if (purebase_notderived) +        Swig_error(Getfile(n), Getline(n), "The javabase typemap for proxy %s must contain just one of the 'replace' or 'notderived' attributes.\n", typemap_lookup_type); +    } else if (Len(pure_baseclass) > 0 && Len(baseclass) > 0) { +      Swig_warning(WARN_JAVA_MULTIPLE_INHERITANCE, Getfile(n), Getline(n), +		   "Warning for %s, base %s ignored. Multiple inheritance is not supported in Java. " +		   "Perhaps you need one of the 'replace' or 'notderived' attributes in the javabase typemap?\n", typemap_lookup_type, pure_baseclass); +    } + +    // Pure Java interfaces +    const String *pure_interfaces = typemapLookup(n, "javainterfaces", typemap_lookup_type, WARN_NONE); + +    if (*Char(interface_list) && *Char(pure_interfaces)) +      Append(interface_list, ", "); +    Append(interface_list, pure_interfaces); +    // Start writing the proxy class +    if (!has_outerclass) // Import statements +      Printv(proxy_class_def, typemapLookup(n, "javaimports", typemap_lookup_type, WARN_NONE),"\n", NIL); + +    // Translate and write javadoc comment if flagged +    if (doxygen && doxygenTranslator->hasDocumentation(n)) { +      String *doxygen_comments = doxygenTranslator->getDocumentation(n, 0); +      if (comment_creation_chatter) +	Printf(proxy_class_def, "/* This was generated from emitProxyClassDefAndCPPCasts() */\n"); +      Printv(proxy_class_def, Char(doxygen_comments), NIL); +      Delete(doxygen_comments); +    } + +    if (has_outerclass) +      Printv(proxy_class_def, "static ", NIL); // C++ nested classes correspond to static java classes +    Printv(proxy_class_def, typemapLookup(n, "javaclassmodifiers", typemap_lookup_type, WARN_JAVA_TYPEMAP_CLASSMOD_UNDEF),	// Class modifiers +	   " $javaclassname",	// Class name and bases +	   (*Char(wanted_base)) ? " extends " : "", wanted_base, *Char(interface_list) ?	// Pure Java interfaces +	   " implements " : "", interface_list, " {", derived ? typemapLookup(n, "javabody_derived", typemap_lookup_type, WARN_JAVA_TYPEMAP_JAVABODY_UNDEF) :	// main body of class +	   typemapLookup(n, "javabody", typemap_lookup_type, WARN_JAVA_TYPEMAP_JAVABODY_UNDEF),	// main body of class +	   NIL); + +    // C++ destructor is wrapped by the delete method +    // Note that the method name is specified in a typemap attribute called methodname +    String *destruct = NewString(""); +    const String *tm = NULL; +    attributes = NewHash(); +    const String *destruct_methodname = NULL; +    const String *destruct_methodmodifiers = NULL; +    const String *destruct_parameters = NULL; +    if (derived) { +      tm = typemapLookup(n, "javadestruct_derived", typemap_lookup_type, WARN_NONE, attributes); +      destruct_methodname = Getattr(attributes, "tmap:javadestruct_derived:methodname"); +      destruct_methodmodifiers = Getattr(attributes, "tmap:javadestruct_derived:methodmodifiers"); +      destruct_parameters = Getattr(attributes, "tmap:javadestruct_derived:parameters"); +    } else { +      tm = typemapLookup(n, "javadestruct", typemap_lookup_type, WARN_NONE, attributes); +      destruct_methodname = Getattr(attributes, "tmap:javadestruct:methodname"); +      destruct_methodmodifiers = Getattr(attributes, "tmap:javadestruct:methodmodifiers"); +      destruct_parameters = Getattr(attributes, "tmap:javadestruct:parameters"); +    } +    if (tm && *Char(tm)) { +      if (!destruct_methodname) { +	Swig_error(Getfile(n), Getline(n), "No methodname attribute defined in javadestruct%s typemap for %s\n", (derived ? "_derived" : ""), proxy_class_name); +      } +      if (!destruct_methodmodifiers) { +	Swig_error(Getfile(n), Getline(n), "No methodmodifiers attribute defined in javadestruct%s typemap for %s.\n", (derived ? "_derived" : ""), proxy_class_name); +      } +      if (!destruct_parameters) +	destruct_parameters = empty_string; +    } +    // Emit the finalize and delete methods +    if (tm) { +      // Finalize method +      if (*Char(destructor_call)) { +	Printv(proxy_class_def, typemapLookup(n, "javafinalize", typemap_lookup_type, WARN_NONE), NIL); +      } +      // delete method +      Printv(destruct, tm, NIL); +      if (*Char(destructor_call)) +	Replaceall(destruct, "$jnicall", destructor_call); +      else +	Replaceall(destruct, "$jnicall", "throw new UnsupportedOperationException(\"C++ destructor does not have public access\")"); +      if (*Char(destruct)) { +	Printv(proxy_class_def, "\n  ", NIL); +	const String *methodmods = Getattr(n, "destructmethodmodifiers"); +	if (methodmods) +	  Printv(proxy_class_def, methodmods, NIL); +	else +	  Printv(proxy_class_def, destruct_methodmodifiers, NIL); +	Printv(proxy_class_def, " void ", destruct_methodname, "(", destruct_parameters, ")", destructor_throws_clause, " ", destruct, "\n", NIL); +      } +    } +    if (*Char(interface_upcasts)) +      Printv(proxy_class_def, interface_upcasts, NIL); + +    /* Insert directordisconnect typemap, if this class has directors enabled */ +    /* Also insert the swigTakeOwnership and swigReleaseOwnership methods */ +    if (feature_director) { +      String *destruct_jnicall, *release_jnicall, *take_jnicall; +      String *changeown_method_name = Swig_name_member(getNSpace(), getClassPrefix(), "change_ownership"); + +      destruct_jnicall = NewStringf("%s()", destruct_methodname); +      release_jnicall = NewStringf("%s.%s(this, swigCPtr, false)", full_imclass_name, changeown_method_name); +      take_jnicall = NewStringf("%s.%s(this, swigCPtr, true)", full_imclass_name, changeown_method_name); + +      emitCodeTypemap(n, false, typemap_lookup_type, "directordisconnect", "methodname", destruct_jnicall); +      emitCodeTypemap(n, false, typemap_lookup_type, "directorowner_release", "methodname", release_jnicall); +      emitCodeTypemap(n, false, typemap_lookup_type, "directorowner_take", "methodname", take_jnicall); + +      Delete(destruct_jnicall); +      Delete(changeown_method_name); +      Delete(release_jnicall); +      Delete(take_jnicall); +    } + +    Delete(interface_upcasts); +    Delete(interface_list); +    Delete(attributes); +    Delete(destruct); + +    // Emit extra user code +    Printv(proxy_class_def, typemapLookup(n, "javacode", typemap_lookup_type, WARN_NONE),	// extra Java code +	   "\n", NIL); + +    if (derived) { +      String *upcast_method_name = Swig_name_member(getNSpace(), getClassPrefix(), smart != 0 ? "SWIGSmartPtrUpcast" : "SWIGUpcast"); +      upcastsCode(smart, upcast_method_name, c_classname, c_baseclassname); +      Delete(upcast_method_name); +    } + +    Delete(smart); +  } + +  /* ---------------------------------------------------------------------- +   * emitInterfaceDeclaration() +   * ---------------------------------------------------------------------- */ + +  void emitInterfaceDeclaration(Node *n, String *interface_name, File *f_interface, String *nspace) { +    if (package || nspace) { +      Printf(f_interface, "package "); +      if (package) +	Printv(f_interface, package, nspace ? "." : "", NIL); +      if (nspace) +	Printv(f_interface, nspace, NIL); +      Printf(f_interface, ";\n"); +    } + +    Printv(f_interface, typemapLookup(n, "javaimports", Getattr(n, "classtypeobj"), WARN_NONE), "\n", NIL); +    Printv(f_interface, typemapLookup(n, "javainterfacemodifiers", Getattr(n, "classtypeobj"), WARN_JAVA_TYPEMAP_INTERFACEMODIFIERS_UNDEF), NIL); +    Printf(f_interface, " %s", interface_name); +    if (List *baselist = Getattr(n, "bases")) { +      String *bases = 0; +      for (Iterator base = First(baselist); base.item; base = Next(base)) { +	if (GetFlag(base.item, "feature:ignore") || !GetFlag(base.item, "feature:interface")) +	  continue; // TODO: warn about skipped non-interface bases +	String *base_iname = Getattr(base.item, "interface:name"); +	if (!bases) +	  bases = Copy(base_iname); +	else { +	  Append(bases, ", "); +	  Append(bases, base_iname); +	} +      } +      if (bases) { +	Printv(f_interface, " extends ", bases, NIL); +	Delete(bases); +      } +    } +    Printf(f_interface, " {\n"); + +    Node *attributes = NewHash(); +    String *interface_code = Copy(typemapLookup(n, "javainterfacecode", Getattr(n, "classtypeobj"), WARN_JAVA_TYPEMAP_INTERFACECODE_UNDEF, attributes)); +    if (interface_code) { +      String *interface_declaration = Copy(Getattr(attributes, "tmap:javainterfacecode:declaration")); +      if (interface_declaration) { +        Replaceall(interface_declaration, "$interfacename", interface_name); +	Printv(f_interface, interface_declaration, NIL); +	Delete(interface_declaration); +      } +      Delete(interface_code); +    } +  } + +  /* ---------------------------------------------------------------------- +  * classDeclaration() +  * ---------------------------------------------------------------------- */ + +  int classDeclaration(Node *n) { +    return Language::classDeclaration(n); +  } + +  /* ---------------------------------------------------------------------- +  * classHandler() +  * ---------------------------------------------------------------------- */ + +  virtual int classHandler(Node *n) { +    File *f_proxy = NULL; +    File *f_interface = NULL; +    String *old_proxy_class_name = proxy_class_name; +    String *old_full_proxy_class_name = full_proxy_class_name; +    String *old_full_imclass_name = full_imclass_name; +    String *old_destructor_call = destructor_call; +    String *old_destructor_throws_clause = destructor_throws_clause; +    String *old_proxy_class_constants_code = proxy_class_constants_code; +    String *old_proxy_class_def = proxy_class_def; +    String *old_proxy_class_code = proxy_class_code; +    bool has_outerclass = Getattr(n, "nested:outer") && !GetFlag(n, "feature:flatnested"); +    String *old_interface_class_code = interface_class_code; +    interface_class_code = 0; + +    if (proxy_flag) { +      proxy_class_name = NewString(Getattr(n, "sym:name")); +      String *nspace = getNSpace(); +      constructIntermediateClassName(n); + +      String *outerClassesPrefix = 0; +      if (Node *outer = Getattr(n, "nested:outer")) { +	outerClassesPrefix = Copy(Getattr(outer, "sym:name")); +	for (outer = Getattr(outer, "nested:outer"); outer != 0; outer = Getattr(outer, "nested:outer")) { +	  Push(outerClassesPrefix, "."); +	  Push(outerClassesPrefix, Getattr(outer, "sym:name")); +	} +      } +      if (!nspace) { +	full_proxy_class_name = outerClassesPrefix ? NewStringf("%s.%s", outerClassesPrefix, proxy_class_name) : NewStringf("%s", proxy_class_name); + +	if (Cmp(proxy_class_name, imclass_name) == 0) { +	  Printf(stderr, "Class name cannot be equal to intermediary class name: %s\n", proxy_class_name); +	  Exit(EXIT_FAILURE); +	} + +	if (Cmp(proxy_class_name, module_class_name) == 0) { +	  Printf(stderr, "Class name cannot be equal to module class name: %s\n", proxy_class_name); +	  Exit(EXIT_FAILURE); +	} +      } else { +	if (outerClassesPrefix) { +	  if (package) +	    full_proxy_class_name = NewStringf("%s.%s.%s.%s", package, nspace, outerClassesPrefix, proxy_class_name); +	  else +	    full_proxy_class_name = NewStringf("%s.%s.%s", nspace, outerClassesPrefix, proxy_class_name); +	} else { +	  if (package) +	    full_proxy_class_name = NewStringf("%s.%s.%s", package, nspace, proxy_class_name); +	  else +	    full_proxy_class_name = NewStringf("%s.%s", nspace, proxy_class_name); +	} +      } + +      String *interface_name = GetFlag(n, "feature:interface") ? Getattr(n, "interface:name") : 0; +      if (outerClassesPrefix) { +	String *fnspace = nspace ? NewStringf("%s.%s", nspace, outerClassesPrefix) : outerClassesPrefix; +	if (!addSymbol(proxy_class_name, n, fnspace)) +	  return SWIG_ERROR; +	if (interface_name && !addInterfaceSymbol(interface_name, n, fnspace)) +	  return SWIG_ERROR; +	if (nspace) +	  Delete(fnspace); +	Delete(outerClassesPrefix); +      } else { +	if (!addSymbol(proxy_class_name, n, nspace)) +	  return SWIG_ERROR; +	if (interface_name && !addInterfaceSymbol(interface_name, n, nspace)) +	  return SWIG_ERROR; +      } + +      // Each outer proxy class goes into a separate file +      if (!has_outerclass) { +	String *output_directory = outputDirectory(nspace); +	String *filen = NewStringf("%s%s.java", output_directory, proxy_class_name); +	f_proxy = NewFile(filen, "w", SWIG_output_files()); +	if (!f_proxy) { +	  FileErrorDisplay(filen); +	  Exit(EXIT_FAILURE); +	} +	Append(filenames_list, Copy(filen)); +	Delete(filen); +	Delete(output_directory); + +	// Start writing out the proxy class file +	emitBanner(f_proxy); + +	if (package || nspace) { +	  Printf(f_proxy, "package "); +	  if (package) +	    Printv(f_proxy, package, nspace ? "." : "", NIL); +	  if (nspace) +	    Printv(f_proxy, nspace, NIL); +	  Printf(f_proxy, ";\n"); +	} +      } +      else +	++nesting_depth; + +      proxy_class_def = NewString(""); +      proxy_class_code = NewString(""); +      destructor_call = NewString(""); +      destructor_throws_clause = NewString(""); +      proxy_class_constants_code = NewString(""); + +      if (GetFlag(n, "feature:interface")) { +        interface_class_code = NewString(""); +	String *output_directory = outputDirectory(nspace); +	String *filen = NewStringf("%s%s.java", output_directory, interface_name); +	f_interface = NewFile(filen, "w", SWIG_output_files()); +	if (!f_interface) { +	  FileErrorDisplay(filen); +	  Exit(EXIT_FAILURE); +	} +	Append(filenames_list, filen); // file name ownership goes to the list +	emitBanner(f_interface); +	emitInterfaceDeclaration(n, interface_name, interface_class_code, nspace); +	Delete(filen); +	Delete(output_directory); +      } +    } + +    Language::classHandler(n); + +    if (proxy_flag) { +      emitProxyClassDefAndCPPCasts(n); + +      String *javaclazzname = Swig_name_member(getNSpace(), getClassPrefix(), ""); // mangled full proxy class name + +      Replaceall(proxy_class_def, "$javaclassname", proxy_class_name); +      Replaceall(proxy_class_code, "$javaclassname", proxy_class_name); +      Replaceall(proxy_class_constants_code, "$javaclassname", proxy_class_name); +      Replaceall(interface_class_code, "$javaclassname", proxy_class_name); + +      Replaceall(proxy_class_def, "$javaclazzname", javaclazzname); +      Replaceall(proxy_class_code, "$javaclazzname", javaclazzname); +      Replaceall(proxy_class_constants_code, "$javaclazzname", javaclazzname); +      Replaceall(interface_class_code, "$javaclazzname", javaclazzname); + +      Replaceall(proxy_class_def, "$module", module_class_name); +      Replaceall(proxy_class_code, "$module", module_class_name); +      Replaceall(proxy_class_constants_code, "$module", module_class_name); +      Replaceall(interface_class_code, "$module", module_class_name); + +      Replaceall(proxy_class_def, "$imclassname", full_imclass_name); +      Replaceall(proxy_class_code, "$imclassname", full_imclass_name); +      Replaceall(proxy_class_constants_code, "$imclassname", full_imclass_name); +      Replaceall(interface_class_code, "$imclassname", full_imclass_name); + +      if (!has_outerclass) +	Printv(f_proxy, proxy_class_def, proxy_class_code, NIL); +      else { +	Swig_offset_string(proxy_class_def, nesting_depth); +	Append(old_proxy_class_code, proxy_class_def); +	Swig_offset_string(proxy_class_code, nesting_depth); +	Append(old_proxy_class_code, proxy_class_code); +      } + +      // Write out all the constants +      if (Len(proxy_class_constants_code) != 0) { +	if (!has_outerclass) +	  Printv(f_proxy, proxy_class_constants_code, NIL); +	else { +	  Swig_offset_string(proxy_class_constants_code, nesting_depth); +	  Append(old_proxy_class_code, proxy_class_constants_code); +	} +      } + +      if (!has_outerclass) { +	Printf(f_proxy, "}\n"); +        Delete(f_proxy); +        f_proxy = NULL; +      } else { +	for (int i = 0; i < nesting_depth; ++i) +	  Append(old_proxy_class_code, "  "); +	Append(old_proxy_class_code, "}\n\n"); +	--nesting_depth; +      } + +      if (f_interface) { +	Printv(f_interface, interface_class_code, "}\n", NIL); +	Delete(f_interface); +	f_interface = 0; +      } + +      emitDirectorExtraMethods(n); + +      Delete(interface_class_code); +      interface_class_code = old_interface_class_code; +      Delete(javaclazzname); +      Delete(proxy_class_name); +      proxy_class_name = old_proxy_class_name; +      Delete(full_proxy_class_name); +      full_proxy_class_name = old_full_proxy_class_name; +      Delete(full_imclass_name); +      full_imclass_name = old_full_imclass_name; +      Delete(destructor_call); +      destructor_call = old_destructor_call; +      Delete(destructor_throws_clause); +      destructor_throws_clause = old_destructor_throws_clause; +      Delete(proxy_class_constants_code); +      proxy_class_constants_code = old_proxy_class_constants_code; +      Delete(proxy_class_def); +      proxy_class_def = old_proxy_class_def; +      Delete(proxy_class_code); +      proxy_class_code = old_proxy_class_code; +    } + +    return SWIG_OK; +  } + +  /* ---------------------------------------------------------------------- +   * memberfunctionHandler() +   * ---------------------------------------------------------------------- */ + +  virtual int memberfunctionHandler(Node *n) { +    member_func_flag = true; +    Language::memberfunctionHandler(n); + +    if (proxy_flag) { +      String *overloaded_name = getOverloadedName(n); +      String *intermediary_function_name = Swig_name_member(getNSpace(), getClassPrefix(), overloaded_name); +      Setattr(n, "proxyfuncname", Getattr(n, "sym:name")); +      Setattr(n, "imfuncname", intermediary_function_name); +      proxyClassFunctionHandler(n); +      Delete(overloaded_name); +    } +    member_func_flag = false; +    return SWIG_OK; +  } + +  /* ---------------------------------------------------------------------- +   * staticmemberfunctionHandler() +   * ---------------------------------------------------------------------- */ + +  virtual int staticmemberfunctionHandler(Node *n) { + +    static_flag = true; +    member_func_flag = true; +    Language::staticmemberfunctionHandler(n); + +    if (proxy_flag) { +      String *overloaded_name = getOverloadedName(n); +      String *intermediary_function_name = Swig_name_member(getNSpace(), getClassPrefix(), overloaded_name); +      Setattr(n, "proxyfuncname", Getattr(n, "sym:name")); +      Setattr(n, "imfuncname", intermediary_function_name); +      proxyClassFunctionHandler(n); +      Delete(overloaded_name); +    } +    static_flag = false; +    member_func_flag = false; + +    return SWIG_OK; +  } + +  /* ----------------------------------------------------------------------------- +   * proxyClassFunctionHandler() +   * +   * Function called for creating a Java wrapper function around a c++ function in the  +   * proxy class. Used for both static and non-static C++ class functions. +   * C++ class static functions map to Java static functions. +   * Two extra attributes in the Node must be available. These are "proxyfuncname" -  +   * the name of the Java class proxy function, which in turn will call "imfuncname" -  +   * the intermediary (JNI) function name in the intermediary class. +   * ----------------------------------------------------------------------------- */ + +  void proxyClassFunctionHandler(Node *n) { +    SwigType *t = Getattr(n, "type"); +    ParmList *l = Getattr(n, "parms"); +    String *intermediary_function_name = Getattr(n, "imfuncname"); +    String *proxy_function_name = Getattr(n, "proxyfuncname"); +    String *tm; +    Parm *p; +    int i; +    String *imcall = NewString(""); +    String *return_type = NewString(""); +    String *function_code = NewString(""); +    bool setter_flag = false; +    String *pre_code = NewString(""); +    String *post_code = NewString(""); +    bool is_interface = GetFlag(parentNode(n), "feature:interface") && !checkAttribute(n, "kind", "variable") +      && !static_flag && Getattr(n, "interface:owner") == 0; + +    if (!proxy_flag) +      return; + +    // Wrappers not wanted for some methods where the parameters cannot be overloaded in Java +    if (Getattr(n, "overload:ignore")) +      return; + +    // Don't generate proxy method for additional explicitcall method used in directors +    if (GetFlag(n, "explicitcall")) +      return; + +    if (l) { +      if (SwigType_type(Getattr(l, "type")) == T_VOID) { +	l = nextSibling(l); +      } +    } + +    /* Attach the non-standard typemaps to the parameter list */ +    Swig_typemap_attach_parms("in", l, NULL); +    Swig_typemap_attach_parms("jtype", l, NULL); +    Swig_typemap_attach_parms("jstype", l, NULL); +    Swig_typemap_attach_parms("javain", l, NULL); + +    /* Get return types */ +    if ((tm = Swig_typemap_lookup("jstype", n, "", 0))) { +      // Note that in the case of polymorphic (covariant) return types, the method's return type is changed to be the base of the C++ return type +      SwigType *covariant = Getattr(n, "covariant"); +      substituteClassname(covariant ? covariant : t, tm); +      Printf(return_type, "%s", tm); +      if (covariant) +	Swig_warning(WARN_JAVA_COVARIANT_RET, input_file, line_number, +		     "Covariant return types not supported in Java. Proxy method will return %s.\n", SwigType_str(covariant, 0)); +    } else { +      Swig_warning(WARN_JAVA_TYPEMAP_JSTYPE_UNDEF, input_file, line_number, "No jstype typemap defined for %s\n", SwigType_str(t, 0)); +    } + +    if (wrapping_member_flag && !enum_constant_flag) { +      // For wrapping member variables (Javabean setter) +      setter_flag = (Cmp(Getattr(n, "sym:name"), Swig_name_set(getNSpace(), Swig_name_member(0, getClassPrefix(), variable_name))) == 0); +    } + +    // Translate and write javadoc comment if flagged +    if (doxygen && doxygenTranslator->hasDocumentation(n)) { +      String *doxygen_comments = doxygenTranslator->getDocumentation(n, "  "); +      if (comment_creation_chatter) +	Printf(function_code, "/* This was generated from proxyclassfunctionhandler() */\n"); +      Printv(function_code, Char(doxygen_comments), NIL); +      Delete(doxygen_comments); +    } + +    /* Start generating the proxy function */ +    const String *methodmods = Getattr(n, "feature:java:methodmodifiers"); +    methodmods = methodmods ? methodmods : (is_public(n) ? public_string : protected_string); +    Printf(function_code, "  %s ", methodmods); +    if (static_flag) +      Printf(function_code, "static "); +    Printf(function_code, "%s %s(", return_type, proxy_function_name); + +    if (is_interface) +      Printf(interface_class_code, "  %s %s(", return_type, proxy_function_name); + +    Printv(imcall, full_imclass_name, ".$imfuncname(", NIL); +    if (!static_flag) { +      Printf(imcall, "swigCPtr"); + +      String *this_type = Copy(getClassType()); +      String *name = NewString("jself"); +      String *qualifier = Getattr(n, "qualifier"); +      if (qualifier) +	SwigType_push(this_type, qualifier); +      SwigType_add_pointer(this_type); +      Parm *this_parm = NewParm(this_type, name, n); +      Swig_typemap_attach_parms("jtype", this_parm, NULL); +      Swig_typemap_attach_parms("jstype", this_parm, NULL); + +      if (prematureGarbageCollectionPreventionParameter(this_type, this_parm)) +	Printf(imcall, ", this"); + +      Delete(this_parm); +      Delete(name); +      Delete(this_type); +    } + +    emit_mark_varargs(l); + +    int gencomma = !static_flag; + +    /* Output each parameter */ +    for (i = 0, p = l; p; i++) { + +      /* Ignored varargs */ +      if (checkAttribute(p, "varargs:ignore", "1")) { +	p = nextSibling(p); +	continue; +      } + +      /* Ignored parameters */ +      if (checkAttribute(p, "tmap:in:numinputs", "0")) { +	p = Getattr(p, "tmap:in:next"); +	continue; +      } + +      /* Ignore the 'this' argument for variable wrappers */ +      if (!(variable_wrapper_flag && i == 0) || static_flag) { +	SwigType *pt = Getattr(p, "type"); +	String *param_type = NewString(""); + +	/* Get the Java parameter type */ +	if ((tm = Getattr(p, "tmap:jstype"))) { +	  substituteClassname(pt, tm); +	  Printf(param_type, "%s", tm); +	} else { +	  Swig_warning(WARN_JAVA_TYPEMAP_JSTYPE_UNDEF, input_file, line_number, "No jstype typemap defined for %s\n", SwigType_str(pt, 0)); +	} + +	if (gencomma) +	  Printf(imcall, ", "); + +	String *arg = makeParameterName(n, p, i, setter_flag); + +	// Use typemaps to transform type used in Java proxy wrapper (in proxy class) to type used in JNI function (in intermediary class) +	if ((tm = Getattr(p, "tmap:javain"))) { +	  addThrows(n, "tmap:javain", p); +	  substituteClassname(pt, tm); +	  Replaceall(tm, "$javainput", arg); +          String *pre = Getattr(p, "tmap:javain:pre"); +          if (pre) { +            substituteClassname(pt, pre); +            Replaceall(pre, "$javainput", arg); +            if (Len(pre_code) > 0) +              Printf(pre_code, "\n"); +            Printv(pre_code, pre, NIL); +          } +          String *post = Getattr(p, "tmap:javain:post"); +          if (post) { +            substituteClassname(pt, post); +            Replaceall(post, "$javainput", arg); +            if (Len(post_code) > 0) +              Printf(post_code, "\n"); +            Printv(post_code, post, NIL); +          } +	  Printv(imcall, tm, NIL); +	} else { +	  Swig_warning(WARN_JAVA_TYPEMAP_JAVAIN_UNDEF, input_file, line_number, "No javain typemap defined for %s\n", SwigType_str(pt, 0)); +	} + +	/* Add parameter to proxy function */ +	if (gencomma >= 2) { +	  Printf(function_code, ", "); +	  if (is_interface) +	    Printf(interface_class_code, ", "); +	} +	gencomma = 2; +	Printf(function_code, "%s %s", param_type, arg); +	if (is_interface) +	  Printf(interface_class_code, "%s %s", param_type, arg); + +	if (prematureGarbageCollectionPreventionParameter(pt, p)) { +          String *pgcppname = Getattr(p, "tmap:javain:pgcppname"); +          if (pgcppname) { +            String *argname = Copy(pgcppname); +            Replaceall(argname, "$javainput", arg); +            Printf(imcall, ", %s", argname); +            Delete(argname); +          } else { +            Printf(imcall, ", %s", arg); +          } +        } + +	Delete(arg); +	Delete(param_type); +      } +      p = Getattr(p, "tmap:in:next"); +    } + +    Printf(imcall, ")"); +    Printf(function_code, ")"); + +    // Transform return type used in JNI function (in intermediary class) to type used in Java wrapper function (in proxy class) +    if ((tm = Swig_typemap_lookup("javaout", n, "", 0))) { +      addThrows(n, "tmap:javaout", n); +      bool is_pre_code = Len(pre_code) > 0; +      bool is_post_code = Len(post_code) > 0; +      if (is_pre_code || is_post_code) { +        Replaceall(tm, "\n ", "\n   "); // add extra indentation to code in typemap +        if (is_post_code) { +          Insert(tm, 0, "\n    try "); +          Printv(tm, " finally {\n", post_code, "\n    }", NIL); +        } else { +          Insert(tm, 0, "\n    "); +        } +        if (is_pre_code) { +          Insert(tm, 0, pre_code); +          Insert(tm, 0, "\n"); +        } +	Insert(tm, 0, "{"); +	Printf(tm, "\n  }"); +      } +      if (GetFlag(n, "feature:new")) +	Replaceall(tm, "$owner", "true"); +      else +	Replaceall(tm, "$owner", "false"); +      substituteClassname(t, tm); + +      // For director methods: generate code to selectively make a normal polymorphic call or  +      // an explicit method call - needed to prevent infinite recursion calls in director methods. +      Node *explicit_n = Getattr(n, "explicitcallnode"); +      if (explicit_n) { +	String *ex_overloaded_name = getOverloadedName(explicit_n); +	String *ex_intermediary_function_name = Swig_name_member(getNSpace(), getClassPrefix(), ex_overloaded_name); + +	String *ex_imcall = Copy(imcall); +	Replaceall(ex_imcall, "$imfuncname", ex_intermediary_function_name); +	Replaceall(imcall, "$imfuncname", intermediary_function_name); + +	String *excode = NewString(""); +	if (!Cmp(return_type, "void")) +	  Printf(excode, "if (getClass() == %s.class) %s; else %s", proxy_class_name, imcall, ex_imcall); +	else +	  Printf(excode, "(getClass() == %s.class) ? %s : %s", proxy_class_name, imcall, ex_imcall); + +	Clear(imcall); +	Printv(imcall, excode, NIL); +	Delete(ex_overloaded_name); +	Delete(excode); +      } else { +	Replaceall(imcall, "$imfuncname", intermediary_function_name); +      } + +      Replaceall(tm, "$imfuncname", intermediary_function_name); +      Replaceall(tm, "$jnicall", imcall); +    } else { +      Swig_warning(WARN_JAVA_TYPEMAP_JAVAOUT_UNDEF, input_file, line_number, "No javaout typemap defined for %s\n", SwigType_str(t, 0)); +    } + +    if (is_interface) { +      Printf(interface_class_code, ")"); +      generateThrowsClause(n, interface_class_code); +      Printf(interface_class_code, ";\n"); +    } +    generateThrowsClause(n, function_code); +    Printf(function_code, " %s\n\n", tm ? tm : empty_string); +    Printv(proxy_class_code, function_code, NIL); + +    Delete(pre_code); +    Delete(post_code); +    Delete(function_code); +    Delete(return_type); +    Delete(imcall); +  } + +  /* ---------------------------------------------------------------------- +   * constructorHandler() +   * ---------------------------------------------------------------------- */ + +  virtual int constructorHandler(Node *n) { + +    ParmList *l = Getattr(n, "parms"); +    String *tm; +    Parm *p; +    int i; +    String *function_code = NewString(""); +    String *helper_code = NewString(""); // Holds code for the constructor helper method generated only when the javain typemap has code in the pre or post attributes +    String *helper_args = NewString(""); +    String *pre_code = NewString(""); +    String *post_code = NewString(""); +    String *im_return_type = NewString(""); +    bool feature_director = (parentNode(n) && Swig_directorclass(n)); + +    Language::constructorHandler(n); + +    // Wrappers not wanted for some methods where the parameters cannot be overloaded in Java +    if (Getattr(n, "overload:ignore")) +      return SWIG_OK; + +    if (proxy_flag) { +      String *overloaded_name = getOverloadedName(n); +      String *mangled_overname = Swig_name_construct(getNSpace(), overloaded_name); +      String *imcall = NewString(""); + +      const String *methodmods = Getattr(n, "feature:java:methodmodifiers"); +      methodmods = methodmods ? methodmods : (is_public(n) ? public_string : protected_string); + +      tm = Getattr(n, "tmap:jtype"); // typemaps were attached earlier to the node +      Printf(im_return_type, "%s", tm); + +      // Translate and write javadoc comment if flagged +      if (doxygen && doxygenTranslator->hasDocumentation(n)) { +	String *doxygen_comments = doxygenTranslator->getDocumentation(n, "  "); +	if (comment_creation_chatter) +	  Printf(function_code, "/* This was generated from constructionhandler() */\n"); +	Printv(function_code, Char(doxygen_comments), NIL); +	Delete(doxygen_comments); +      } + +      Printf(function_code, "  %s %s(", methodmods, proxy_class_name); +      Printf(helper_code, "  static private %s SwigConstruct%s(", im_return_type, proxy_class_name); + +      Printv(imcall, full_imclass_name, ".", mangled_overname, "(", NIL); + +      /* Attach the non-standard typemaps to the parameter list */ +      Swig_typemap_attach_parms("in", l, NULL); +      Swig_typemap_attach_parms("jtype", l, NULL); +      Swig_typemap_attach_parms("jstype", l, NULL); +      Swig_typemap_attach_parms("javain", l, NULL); + +      emit_mark_varargs(l); + +      int gencomma = 0; + +      /* Output each parameter */ +      for (i = 0, p = l; p; i++) { + +	/* Ignored varargs */ +	if (checkAttribute(p, "varargs:ignore", "1")) { +	  p = nextSibling(p); +	  continue; +	} + +	/* Ignored parameters */ +	if (checkAttribute(p, "tmap:in:numinputs", "0")) { +	  p = Getattr(p, "tmap:in:next"); +	  continue; +	} + +	SwigType *pt = Getattr(p, "type"); +	String *param_type = NewString(""); + +	/* Get the Java parameter type */ +	if ((tm = Getattr(p, "tmap:jstype"))) { +	  substituteClassname(pt, tm); +	  Printf(param_type, "%s", tm); +	} else { +	  Swig_warning(WARN_JAVA_TYPEMAP_JSTYPE_UNDEF, input_file, line_number, "No jstype typemap defined for %s\n", SwigType_str(pt, 0)); +	} + +	if (gencomma) +	  Printf(imcall, ", "); + +	String *arg = makeParameterName(n, p, i, false); + +	// Use typemaps to transform type used in Java wrapper function (in proxy class) to type used in JNI function (in intermediary class) +	if ((tm = Getattr(p, "tmap:javain"))) { +	  addThrows(n, "tmap:javain", p); +	  substituteClassname(pt, tm); +	  Replaceall(tm, "$javainput", arg); +          String *pre = Getattr(p, "tmap:javain:pre"); +          if (pre) { +            substituteClassname(pt, pre); +            Replaceall(pre, "$javainput", arg); +            if (Len(pre_code) > 0) +              Printf(pre_code, "\n"); +            Printv(pre_code, pre, NIL); +          } +          String *post = Getattr(p, "tmap:javain:post"); +          if (post) { +            substituteClassname(pt, post); +            Replaceall(post, "$javainput", arg); +            if (Len(post_code) > 0) +              Printf(post_code, "\n"); +            Printv(post_code, post, NIL); +          } +	  Printv(imcall, tm, NIL); +	} else { +	  Swig_warning(WARN_JAVA_TYPEMAP_JAVAIN_UNDEF, input_file, line_number, "No javain typemap defined for %s\n", SwigType_str(pt, 0)); +	} + +	/* Add parameter to proxy function */ +	if (gencomma) { +	  Printf(function_code, ", "); +	  Printf(helper_code, ", "); +	  Printf(helper_args, ", "); +        } +	Printf(function_code, "%s %s", param_type, arg); +	Printf(helper_code, "%s %s", param_type, arg); +	Printf(helper_args, "%s", arg); +	++gencomma; + +	if (prematureGarbageCollectionPreventionParameter(pt, p)) { +          String *pgcppname = Getattr(p, "tmap:javain:pgcppname"); +          if (pgcppname) { +            String *argname = Copy(pgcppname); +            Replaceall(argname, "$javainput", arg); +            Printf(imcall, ", %s", argname); +            Delete(argname); +          } else { +            Printf(imcall, ", %s", arg); +          } +        } + +	Delete(arg); +	Delete(param_type); +	p = Getattr(p, "tmap:in:next"); +      } + +      Printf(imcall, ")"); + +      Printf(function_code, ")"); +      Printf(helper_code, ")"); +      generateThrowsClause(n, function_code); + +      /* Insert the javaconstruct typemap, doing the replacement for $directorconnect, as needed */ +      Hash *attributes = NewHash(); +      String *typemap_lookup_type = Getattr(getCurrentClass(), "classtypeobj"); +      String *construct_tm = Copy(typemapLookup(n, "javaconstruct", typemap_lookup_type, +						WARN_JAVA_TYPEMAP_JAVACONSTRUCT_UNDEF, attributes)); +      if (construct_tm) { +	if (!feature_director) { +	  Replaceall(construct_tm, "$directorconnect", ""); +	} else { +	  String *connect_attr = Getattr(attributes, "tmap:javaconstruct:directorconnect"); + +	  if (connect_attr) { +	    Replaceall(construct_tm, "$directorconnect", connect_attr); +	  } else { +	    Swig_warning(WARN_JAVA_NO_DIRECTORCONNECT_ATTR, input_file, line_number, "\"directorconnect\" attribute missing in %s \"javaconstruct\" typemap.\n", +			 Getattr(n, "name")); +	    Replaceall(construct_tm, "$directorconnect", ""); +	  } +	} + +	Printv(function_code, " ", construct_tm, "\n", NIL); +      } + +      bool is_pre_code = Len(pre_code) > 0; +      bool is_post_code = Len(post_code) > 0; +      if (is_pre_code || is_post_code) { +        generateThrowsClause(n, helper_code); +        Printf(helper_code, " {\n"); +        if (is_pre_code) { +          Printv(helper_code, pre_code, "\n", NIL); +        } +        if (is_post_code) { +          Printf(helper_code, "    try {\n"); +          Printv(helper_code, "      return ", imcall, ";\n", NIL); +          Printv(helper_code, "    } finally {\n", post_code, "\n    }", NIL); +        } else { +          Printv(helper_code, "    return ", imcall, ";", NIL); +        } +        Printf(helper_code, "\n  }\n"); +        String *helper_name = NewStringf("%s.SwigConstruct%s(%s)", proxy_class_name, proxy_class_name, helper_args); +        Printv(proxy_class_code, helper_code, "\n", NIL); +        Replaceall(function_code, "$imcall", helper_name); +        Delete(helper_name); +      } else { +        Replaceall(function_code, "$imcall", imcall); +      } + +      Printv(proxy_class_code, function_code, "\n", NIL); + +      Delete(helper_args); +      Delete(im_return_type); +      Delete(pre_code); +      Delete(post_code); +      Delete(construct_tm); +      Delete(attributes); +      Delete(overloaded_name); +      Delete(imcall); +    } + +    return SWIG_OK; +  } + +  /* ---------------------------------------------------------------------- +   * destructorHandler() +   * ---------------------------------------------------------------------- */ + +  virtual int destructorHandler(Node *n) { +    Language::destructorHandler(n); +    String *symname = Getattr(n, "sym:name"); + +    if (proxy_flag) { +      Printv(destructor_call, full_imclass_name, ".", Swig_name_destroy(getNSpace(), symname), "(swigCPtr)", NIL); +      generateThrowsClause(n, destructor_throws_clause); +      const String *methodmods = Getattr(n, "feature:java:methodmodifiers"); +      if (methodmods) +	Setattr(getCurrentClass(), "destructmethodmodifiers", methodmods); +    } +    return SWIG_OK; +  } + +  /* ---------------------------------------------------------------------- +   * membervariableHandler() +   * ---------------------------------------------------------------------- */ + +  virtual int membervariableHandler(Node *n) { +    variable_name = Getattr(n, "sym:name"); +    wrapping_member_flag = true; +    variable_wrapper_flag = true; +    Language::membervariableHandler(n); +    wrapping_member_flag = false; +    variable_wrapper_flag = false; +    return SWIG_OK; +  } + +  /* ---------------------------------------------------------------------- +   * staticmembervariableHandler() +   * ---------------------------------------------------------------------- */ + +  virtual int staticmembervariableHandler(Node *n) { +    variable_name = Getattr(n, "sym:name"); +    wrapping_member_flag = true; +    static_flag = true; +    Language::staticmembervariableHandler(n); +    wrapping_member_flag = false; +    static_flag = false; +    return SWIG_OK; +  } + +  /* ---------------------------------------------------------------------- +   * memberconstantHandler() +   * ---------------------------------------------------------------------- */ + +  virtual int memberconstantHandler(Node *n) { +    variable_name = Getattr(n, "sym:name"); +    wrapping_member_flag = true; +    Language::memberconstantHandler(n); +    wrapping_member_flag = false; +    return SWIG_OK; +  } + +  /* ----------------------------------------------------------------------------- +   * getOverloadedName() +   * ----------------------------------------------------------------------------- */ + +  String *getOverloadedName(Node *n) { + +    /* Although JNI functions are designed to handle overloaded Java functions, +     * a Java long is used for all classes in the SWIG intermediary class. +     * The intermediary class methods are thus mangled when overloaded to give +     * a unique name. */ +    String *overloaded_name = NewStringf("%s", Getattr(n, "sym:name")); + +    if (Getattr(n, "sym:overloaded")) { +      Printv(overloaded_name, Getattr(n, "sym:overname"), NIL); +    } + +    return overloaded_name; +  } + +  /* ----------------------------------------------------------------------------- +   * moduleClassFunctionHandler() +   * ----------------------------------------------------------------------------- */ + +  void moduleClassFunctionHandler(Node *n) { +    SwigType *t = Getattr(n, "type"); +    ParmList *l = Getattr(n, "parms"); +    String *tm; +    Parm *p; +    int i; +    String *imcall = NewString(""); +    String *return_type = NewString(""); +    String *function_code = NewString(""); +    int num_arguments = 0; +    String *overloaded_name = getOverloadedName(n); +    String *func_name = NULL; +    bool setter_flag = false; +    String *pre_code = NewString(""); +    String *post_code = NewString(""); + +    // Translate and write javadoc comment if flagged +    if (doxygen && doxygenTranslator->hasDocumentation(n)) { +      String *doxygen_comments = doxygenTranslator->getDocumentation(n, "  "); +      if (comment_creation_chatter) +	Printf(function_code, "/* This was generated from moduleClassFunctionHandler() */\n"); +      Printv(function_code, doxygen_comments, NIL); +      Delete(doxygen_comments); +    } + +    if (l) { +      if (SwigType_type(Getattr(l, "type")) == T_VOID) { +	l = nextSibling(l); +      } +    } + +    /* Attach the non-standard typemaps to the parameter list */ +    Swig_typemap_attach_parms("jstype", l, NULL); +    Swig_typemap_attach_parms("javain", l, NULL); + +    /* Get return types */ +    if ((tm = Swig_typemap_lookup("jstype", n, "", 0))) { +      substituteClassname(t, tm); +      Printf(return_type, "%s", tm); +    } else { +      Swig_warning(WARN_JAVA_TYPEMAP_JSTYPE_UNDEF, input_file, line_number, "No jstype typemap defined for %s\n", SwigType_str(t, 0)); +    } + +    /* Change function name for global variables */ +    if (proxy_flag && global_variable_flag) { +      // Capitalize the first letter in the variable to create a JavaBean type getter/setter function name +      func_name = NewString(""); +      setter_flag = (Cmp(Getattr(n, "sym:name"), Swig_name_set(getNSpace(), variable_name)) == 0); +      if (setter_flag) +	Printf(func_name, "set"); +      else +	Printf(func_name, "get"); +      Putc(toupper((int) *Char(variable_name)), func_name); +      Printf(func_name, "%s", Char(variable_name) + 1); +    } else { +      func_name = Copy(Getattr(n, "sym:name")); +    } + +    /* Start generating the function */ +    const String *methodmods = Getattr(n, "feature:java:methodmodifiers"); +    methodmods = methodmods ? methodmods : (is_public(n) ? public_string : protected_string); +    Printf(function_code, "  %s static %s %s(", methodmods, return_type, func_name); +    Printv(imcall, imclass_name, ".", overloaded_name, "(", NIL); + +    /* Get number of required and total arguments */ +    num_arguments = emit_num_arguments(l); + +    bool global_or_member_variable = global_variable_flag || (wrapping_member_flag && !enum_constant_flag); +    int gencomma = 0; + +    /* Output each parameter */ +    for (i = 0, p = l; i < num_arguments; i++) { + +      /* Ignored parameters */ +      while (checkAttribute(p, "tmap:in:numinputs", "0")) { +	p = Getattr(p, "tmap:in:next"); +      } + +      SwigType *pt = Getattr(p, "type"); +      String *param_type = NewString(""); + +      /* Get the Java parameter type */ +      if ((tm = Getattr(p, "tmap:jstype"))) { +	substituteClassname(pt, tm); +	Printf(param_type, "%s", tm); +      } else { +	Swig_warning(WARN_JAVA_TYPEMAP_JSTYPE_UNDEF, input_file, line_number, "No jstype typemap defined for %s\n", SwigType_str(pt, 0)); +      } + +      if (gencomma) +	Printf(imcall, ", "); + +      String *arg = makeParameterName(n, p, i, global_or_member_variable); + +      // Use typemaps to transform type used in Java wrapper function (in proxy class) to type used in JNI function (in intermediary class) +      if ((tm = Getattr(p, "tmap:javain"))) { +	addThrows(n, "tmap:javain", p); +	substituteClassname(pt, tm); +	Replaceall(tm, "$javainput", arg); +	String *pre = Getattr(p, "tmap:javain:pre"); +	if (pre) { +	  substituteClassname(pt, pre); +	  Replaceall(pre, "$javainput", arg); +          if (Len(pre_code) > 0) +            Printf(pre_code, "\n"); +	  Printv(pre_code, pre, NIL); +	} +	String *post = Getattr(p, "tmap:javain:post"); +	if (post) { +	  substituteClassname(pt, post); +	  Replaceall(post, "$javainput", arg); +          if (Len(post_code) > 0) +            Printf(post_code, "\n"); +	  Printv(post_code, post, NIL); +	} +	Printv(imcall, tm, NIL); +      } else { +	Swig_warning(WARN_JAVA_TYPEMAP_JAVAIN_UNDEF, input_file, line_number, "No javain typemap defined for %s\n", SwigType_str(pt, 0)); +      } + +      /* Add parameter to module class function */ +      if (gencomma >= 2) +	Printf(function_code, ", "); +      gencomma = 2; +      Printf(function_code, "%s %s", param_type, arg); + +      if (prematureGarbageCollectionPreventionParameter(pt, p)) { +        String *pgcppname = Getattr(p, "tmap:javain:pgcppname"); +        if (pgcppname) { +          String *argname = Copy(pgcppname); +          Replaceall(argname, "$javainput", arg); +          Printf(imcall, ", %s", argname); +          Delete(argname); +        } else { +          Printf(imcall, ", %s", arg); +        } +      } + +      p = Getattr(p, "tmap:in:next"); +      Delete(arg); +      Delete(param_type); +    } + +    Printf(imcall, ")"); +    Printf(function_code, ")"); + +    // Transform return type used in JNI function (in intermediary class) to type used in Java wrapper function (in module class) +    if ((tm = Swig_typemap_lookup("javaout", n, "", 0))) { +      addThrows(n, "tmap:javaout", n); +      bool is_pre_code = Len(pre_code) > 0; +      bool is_post_code = Len(post_code) > 0; +      if (is_pre_code || is_post_code) { +        Replaceall(tm, "\n ", "\n   "); // add extra indentation to code in typemap +        if (is_post_code) { +          Insert(tm, 0, "\n    try "); +          Printv(tm, " finally {\n", post_code, "\n    }", NIL); +        } else { +          Insert(tm, 0, "\n    "); +        } +        if (is_pre_code) { +          Insert(tm, 0, pre_code); +          Insert(tm, 0, "\n"); +        } +	Insert(tm, 0, "{"); +	Printf(tm, "\n  }"); +      } +      if (GetFlag(n, "feature:new")) +	Replaceall(tm, "$owner", "true"); +      else +	Replaceall(tm, "$owner", "false"); +      substituteClassname(t, tm); +      Replaceall(tm, "$imfuncname", overloaded_name); +      Replaceall(tm, "$jnicall", imcall); +    } else { +      Swig_warning(WARN_JAVA_TYPEMAP_JAVAOUT_UNDEF, input_file, line_number, "No javaout typemap defined for %s\n", SwigType_str(t, 0)); +    } + +    generateThrowsClause(n, function_code); +    Printf(function_code, " %s\n\n", tm ? tm : empty_string); +    Printv(module_class_code, function_code, NIL); + +    Delete(pre_code); +    Delete(post_code); +    Delete(function_code); +    Delete(return_type); +    Delete(imcall); +    Delete(func_name); +  } + +  /*---------------------------------------------------------------------- +   * replaceSpecialVariables() +   *--------------------------------------------------------------------*/ + +  virtual void replaceSpecialVariables(String *method, String *tm, Parm *parm) { +    (void)method; +    SwigType *type = Getattr(parm, "type"); +    substituteClassname(type, tm); +  } + +  /*---------------------------------------------------------------------- +   * decodeEnumFeature() +   * Decode the possible enum features, which are one of: +   *   %javaenum(simple) +   *   %javaenum(typeunsafe) - default +   *   %javaenum(typesafe) +   *   %javaenum(proper) +   *--------------------------------------------------------------------*/ + +  EnumFeature decodeEnumFeature(Node *n) { +    EnumFeature enum_feature = TypeunsafeEnum; +    String *feature = Getattr(n, "feature:java:enum"); +    if (feature) { +      if (Cmp(feature, "simple") == 0) +	enum_feature = SimpleEnum; +      else if (Cmp(feature, "typesafe") == 0) +	enum_feature = TypesafeEnum; +      else if (Cmp(feature, "proper") == 0) +	enum_feature = ProperEnum; +    } +    return enum_feature; +  } + +  /* ----------------------------------------------------------------------- +   * enumValue() +   * This method will return a string with an enum value to use in Java generated +   * code. If the %javaconst feature is not used, the string will contain the intermediary +   * class call to obtain the enum value. The intermediary class and JNI methods to obtain +   * the enum value will be generated. Otherwise the C/C++ enum value will be used if there +   * is one and hopefully it will compile as Java code - e.g. 20 as in: enum E{e=20}; +   * The %javaconstvalue feature overrides all other ways to generate the constant value. +   * The caller must delete memory allocated for the returned string. +   * ------------------------------------------------------------------------ */ + +  String *enumValue(Node *n) { +    String *symname = Getattr(n, "sym:name"); + +    // Check for the %javaconstvalue feature +    String *value = Getattr(n, "feature:java:constvalue"); + +    if (!value) { +      // The %javaconst feature determines how the constant value is obtained +      int const_feature_flag = GetFlag(n, "feature:java:const"); + +      if (const_feature_flag) { +	// Use the C syntax to make a true Java constant and hope that it compiles as Java code +	value = Getattr(n, "enumvalue") ? Copy(Getattr(n, "enumvalue")) : Copy(Getattr(n, "enumvalueex")); +      } else { +	String *newsymname = 0; +	if (!getCurrentClass() || !proxy_flag) { +	  String *enumClassPrefix = getEnumClassPrefix(); +	  if (enumClassPrefix) { +	    // A global scoped enum +	    newsymname = Swig_name_member(0, enumClassPrefix, symname); +	    symname = newsymname; +	  } +	} + +	// Get the enumvalue from a JNI call +	if (!getCurrentClass() || !cparse_cplusplus || !proxy_flag) { +	  // Strange hack to change the name +	  Setattr(n, "name", Getattr(n, "value"));	/* for wrapping of enums in a namespace when emit_action is used */ +	  constantWrapper(n); +	  value = NewStringf("%s.%s()", full_imclass_name ? full_imclass_name : imclass_name, Swig_name_get(getNSpace(), symname)); +	} else { +	  memberconstantHandler(n); +	  value = NewStringf("%s.%s()", full_imclass_name ? full_imclass_name : imclass_name, Swig_name_get(getNSpace(), Swig_name_member(0, getEnumClassPrefix(), symname))); +	} +	Delete(newsymname); +      } +    } +    return value; +  } + +  /* ----------------------------------------------------------------------------- +   * getEnumName() +   * +   * If jnidescriptor is set, inner class names are separated with '$' otherwise a '.' +   * and the package is also not added to the name. +   * ----------------------------------------------------------------------------- */ + +  String *getEnumName(SwigType *t, bool jnidescriptor) { +    Node *enumname = NULL; +    Node *n = enumLookup(t); +    if (n) { +      enumname = Getattr(n, "enumname"); +      if (!enumname || jnidescriptor) { +	String *symname = Getattr(n, "sym:name"); +	if (symname) { +	  // Add in class scope when referencing enum if not a global enum +	  String *scopename_prefix = Swig_scopename_prefix(Getattr(n, "name")); +	  String *proxyname = 0; +	  if (scopename_prefix) { +	    proxyname = getProxyName(scopename_prefix, jnidescriptor); +	  } +	  if (proxyname) { +	    const char *class_separator = jnidescriptor ? "$" : "."; +	    enumname = NewStringf("%s%s%s", proxyname, class_separator, symname); +	  } else { +	    // global enum or enum in a namespace +	    String *nspace = Getattr(n, "sym:nspace"); +	    if (nspace) { +	      if (package && !jnidescriptor) +		enumname = NewStringf("%s.%s.%s", package, nspace, symname); +	      else +		enumname = NewStringf("%s.%s", nspace, symname); +	    } else { +	      enumname = Copy(symname); +	    } +	  } +	  if (!jnidescriptor) { +	    Setattr(n, "enumname", enumname); // Cache it +	    Delete(enumname); +	  } +	  Delete(scopename_prefix); +	} +      } +    } + +    return enumname; +  } + +  /* ----------------------------------------------------------------------------- +   * substituteClassname() +   * +   * Substitute the special variable $javaclassname with the proxy class name for classes/structs/unions  +   * that SWIG knows about. Also substitutes enums with enum name. +   * Otherwise use the $descriptor name for the Java class name. Note that the $&javaclassname substitution +   * is the same as a $&descriptor substitution, ie one pointer added to descriptor name. +   * Note that the path separator is a '.' unless jnidescriptor is set. +   * Inputs: +   *   pt - parameter type +   *   tm - typemap contents that might contain the special variable to be replaced +   *   jnidescriptor - if set, inner class names are separated with '$' otherwise a '/' is used for the path separator +   * Outputs: +   *   tm - typemap contents complete with the special variable substitution +   * Return: +   *   substitution_performed - flag indicating if a substitution was performed +   * ----------------------------------------------------------------------------- */ + +  bool substituteClassname(SwigType *pt, String *tm, bool jnidescriptor = false) { +    bool substitution_performed = false; +    SwigType *type = Copy(SwigType_typedef_resolve_all(pt)); +    SwigType *strippedtype = SwigType_strip_qualifiers(type); + +    if (Strstr(tm, "$javaclassname")) { +      SwigType *classnametype = Copy(strippedtype); +      substituteClassnameSpecialVariable(classnametype, tm, "$javaclassname", jnidescriptor); +      substitution_performed = true; +      Delete(classnametype); +    } +    if (Strstr(tm, "$*javaclassname")) { +      SwigType *classnametype = Copy(strippedtype); +      Delete(SwigType_pop(classnametype)); +      if (Len(classnametype) > 0) { +	substituteClassnameSpecialVariable(classnametype, tm, "$*javaclassname", jnidescriptor); +	substitution_performed = true; +      } +      Delete(classnametype); +    } +    if (Strstr(tm, "$&javaclassname")) { +      SwigType *classnametype = Copy(strippedtype); +      SwigType_add_pointer(classnametype); +      substituteClassnameSpecialVariable(classnametype, tm, "$&javaclassname", jnidescriptor); +      substitution_performed = true; +      Delete(classnametype); +    } +    if (Strstr(tm, "$javainterfacename")) { +      SwigType *interfacenametype = Copy(strippedtype); +      substituteInterfacenameSpecialVariable(interfacenametype, tm, "$javainterfacename", jnidescriptor, true); +      substitution_performed = true; +      Delete(interfacenametype); +    } +    if (Strstr(tm, "$*javainterfacename")) { +      SwigType *interfacenametype = Copy(strippedtype); +      Delete(SwigType_pop(interfacenametype)); +      if (Len(interfacenametype) > 0) { +	substituteInterfacenameSpecialVariable(interfacenametype, tm, "$*javainterfacename", jnidescriptor, true); +	substitution_performed = true; +      } +      Delete(interfacenametype); +    } +    if (Strstr(tm, "$&javainterfacename")) { +      SwigType *interfacenametype = Copy(strippedtype); +      SwigType_add_pointer(interfacenametype); +      substituteInterfacenameSpecialVariable(interfacenametype, tm, "$&javainterfacename", jnidescriptor, true); +      substitution_performed = true; +      Delete(interfacenametype); +    } +    if (Strstr(tm, "$interfacename")) { +      SwigType *interfacenametype = Copy(strippedtype); +      substituteInterfacenameSpecialVariable(interfacenametype, tm, "$interfacename", jnidescriptor, false); +      substitution_performed = true; +      Delete(interfacenametype); +    } +    if (Strstr(tm, "$*interfacename")) { +      SwigType *interfacenametype = Copy(strippedtype); +      Delete(SwigType_pop(interfacenametype)); +      if (Len(interfacenametype) > 0) { +	substituteInterfacenameSpecialVariable(interfacenametype, tm, "$*interfacename", jnidescriptor, false); +	substitution_performed = true; +      } +      Delete(interfacenametype); +    } +    if (Strstr(tm, "$&interfacename")) { +      SwigType *interfacenametype = Copy(strippedtype); +      SwigType_add_pointer(interfacenametype); +      substituteInterfacenameSpecialVariable(interfacenametype, tm, "$&interfacename", jnidescriptor, false); +      substitution_performed = true; +      Delete(interfacenametype); +    } + +    Delete(strippedtype); +    Delete(type); + +    return substitution_performed; +  } + +  /* ----------------------------------------------------------------------------- +   * substituteClassnameSpecialVariable() +   * ----------------------------------------------------------------------------- */ + +  void substituteClassnameSpecialVariable(SwigType *classnametype, String *tm, const char *classnamespecialvariable, bool jnidescriptor) { +    String *replacementname; + +    if (SwigType_isenum(classnametype)) { +      String *enumname = getEnumName(classnametype, jnidescriptor); +      if (enumname) { +	replacementname = Copy(enumname); +      } else { +        bool anonymous_enum = (Cmp(classnametype, "enum ") == 0); +	if (anonymous_enum) { +	  replacementname = NewString("int"); +	} else { +	  // An unknown enum - one that has not been parsed (neither a C enum forward reference nor a definition) or an ignored enum +	  replacementname = NewStringf("SWIGTYPE%s", SwigType_manglestr(classnametype)); +	  Replace(replacementname, "enum ", "", DOH_REPLACE_ANY); +	  Setattr(swig_types_hash, replacementname, classnametype); +	} +      } +    } else { +      String *classname = getProxyName(classnametype, jnidescriptor); // getProxyName() works for pointers to classes too +      if (classname) { +	replacementname = Copy(classname); +      } else { +	// use $descriptor if SWIG does not know anything about this type. Note that any typedefs are resolved. +	replacementname = NewStringf("SWIGTYPE%s", SwigType_manglestr(classnametype)); + +	// Add to hash table so that the type wrapper classes can be created later +	Setattr(swig_types_hash, replacementname, classnametype); +      } +    } +    if (jnidescriptor) +      Replaceall(replacementname,".","/"); +    Replaceall(tm, classnamespecialvariable, replacementname); + +    Delete(replacementname); +  } + +  /* ----------------------------------------------------------------------------- +   * substituteInterfacenameSpecialVariable() +   * ----------------------------------------------------------------------------- */ + +  void substituteInterfacenameSpecialVariable(SwigType *interfacenametype, String *tm, const char *interfacenamespecialvariable, bool jnidescriptor, bool qualified) { + +    String *interfacename = getInterfaceName(interfacenametype/*, jnidescriptor*/, qualified); +    if (interfacename) { +      String *replacementname = Copy(interfacename); + +      if (jnidescriptor) +	Replaceall(replacementname,".","/"); +      Replaceall(tm, interfacenamespecialvariable, replacementname); + +      Delete(replacementname); +    } +  } + +  /* ----------------------------------------------------------------------------- +   * emitTypeWrapperClass() +   * ----------------------------------------------------------------------------- */ + +  void emitTypeWrapperClass(String *classname, SwigType *type) { +    Node *n = NewHash(); +    Setfile(n, input_file); +    Setline(n, line_number); + +    String *swigtype = NewString(""); +    String *filen = NewStringf("%s%s.java", SWIG_output_directory(), classname); +    File *f_swigtype = NewFile(filen, "w", SWIG_output_files()); +    if (!f_swigtype) { +      FileErrorDisplay(filen); +      Exit(EXIT_FAILURE); +    } +    Append(filenames_list, Copy(filen)); +    Delete(filen); +    filen = NULL; + +    // Start writing out the type wrapper class file +    emitBanner(f_swigtype); + +    if (package) +      Printf(f_swigtype, "package %s;\n", package); + +    // Pure Java baseclass and interfaces +    const String *pure_baseclass = typemapLookup(n, "javabase", type, WARN_NONE); +    const String *pure_interfaces = typemapLookup(n, "javainterfaces", type, WARN_NONE); + +    // Emit the class +    Printv(swigtype, typemapLookup(n, "javaimports", type, WARN_NONE),	// Import statements +	   "\n", typemapLookup(n, "javaclassmodifiers", type, WARN_JAVA_TYPEMAP_CLASSMOD_UNDEF),	// Class modifiers +	   " $javaclassname",	// Class name and bases +	   *Char(pure_baseclass) ? " extends " : "", pure_baseclass, *Char(pure_interfaces) ?	// Interfaces +	   " implements " : "", pure_interfaces, " {", typemapLookup(n, "javabody", type, WARN_JAVA_TYPEMAP_JAVABODY_UNDEF),	// main body of class +	   typemapLookup(n, "javacode", type, WARN_NONE),	// extra Java code +	   "}\n", "\n", NIL); + +    Replaceall(swigtype, "$javaclassname", classname); +    Replaceall(swigtype, "$module", module_class_name); +    Replaceall(swigtype, "$imclassname", imclass_name); + +    // For unknown enums +    Replaceall(swigtype, "$static ", ""); +    Replaceall(swigtype, "$enumvalues", ""); + +    Printv(f_swigtype, swigtype, NIL); + +    Delete(f_swigtype); +    Delete(swigtype); +    Delete(n); +  } + +  /* ----------------------------------------------------------------------------- +   * typemapLookup() +   * n - for input only and must contain info for Getfile(n) and Getline(n) to work +   * tmap_method - typemap method name +   * type - typemap type to lookup +   * warning - warning number to issue if no typemaps found +   * typemap_attributes - the typemap attributes are attached to this node and will  +   *   also be used for temporary storage if non null +   * return is never NULL, unlike Swig_typemap_lookup() +   * ----------------------------------------------------------------------------- */ + +  const String *typemapLookup(Node *n, const_String_or_char_ptr tmap_method, SwigType *type, int warning, Node *typemap_attributes = 0) { +    Node *node = !typemap_attributes ? NewHash() : typemap_attributes; +    Setattr(node, "type", type); +    Setfile(node, Getfile(n)); +    Setline(node, Getline(n)); +    const String *tm = Swig_typemap_lookup(tmap_method, node, "", 0); +    if (!tm) { +      tm = empty_string; +      if (warning != WARN_NONE) +	Swig_warning(warning, Getfile(n), Getline(n), "No %s typemap defined for %s\n", tmap_method, SwigType_str(type, 0)); +    } +    if (!typemap_attributes) +      Delete(node); +    return tm; +  } + +  /* ----------------------------------------------------------------------------- +   * addThrows() +   * +   * Adds exception classes to a throws list. The throws list is the list of classes +   * that will form the Java throws clause. Mainly for checked exceptions. +   * ----------------------------------------------------------------------------- */ + +  void addThrows(Node *n, const String *attribute, Node *parameter) { +    // Get the comma separated exception classes for the throws clause - held in typemap/feature's "throws" attribute +    String *throws_attribute = NewStringf("%s:throws", attribute); +    String *throws = Getattr(parameter, throws_attribute); + +    if (throws && Len(throws) > 0) { +      String *throws_list = Getattr(n, "java:throwslist"); +      if (!throws_list) { +	throws_list = NewList(); +	Setattr(n, "java:throwslist", throws_list); +      } +      // Put the exception classes in the throws clause into a temporary List +      List *temp_classes_list = Split(throws, ',', INT_MAX); + +      // Add the exception classes to the node throws list, but don't duplicate if already in list +      if (temp_classes_list && Len(temp_classes_list) > 0) { +	for (Iterator cls = First(temp_classes_list); cls.item; cls = Next(cls)) { +	  String *exception_class = NewString(cls.item); +	  Replaceall(exception_class, " ", "");	// remove spaces +	  Replaceall(exception_class, "\t", "");	// remove tabs +	  if (Len(exception_class) > 0) { +	    // $javaclassname substitution +	    SwigType *pt = Getattr(parameter, "type"); +	    substituteClassname(pt, exception_class); + +	    // Don't duplicate the Java exception class in the throws clause +	    bool found_flag = false; +	    for (Iterator item = First(throws_list); item.item; item = Next(item)) { +	      if (Strcmp(item.item, exception_class) == 0) +		found_flag = true; +	    } +	    if (!found_flag) +	      Append(throws_list, exception_class); +	  } +	  Delete(exception_class); +	} +      } +      Delete(temp_classes_list); +    } +    Delete(throws_attribute); +  } + +  /* ----------------------------------------------------------------------------- +   * generateThrowsClause() +   * +   * Generates throws clause for checked exception +   * ----------------------------------------------------------------------------- */ + +  void generateThrowsClause(Node *n, String *code) { +    // Add the throws clause into code +    List *throws_list = Getattr(n, "java:throwslist"); +    if (throws_list) { +      Iterator cls = First(throws_list); +      Printf(code, " throws %s", cls.item); +      while ((cls = Next(cls)).item) +	Printf(code, ", %s", cls.item); +    } +  } + +  /* ----------------------------------------------------------------------------- +   * prematureGarbageCollectionPreventionParameter() +   * +   * Get the proxy class name for use in an additional generated parameter. The +   * additional parameter is added to a native method call purely to prevent  +   * premature garbage collection of proxy classes which pass their C++ class pointer +   * in a Java long to the JNI layer. +   * ----------------------------------------------------------------------------- */ + +  String *prematureGarbageCollectionPreventionParameter(SwigType *t, Parm *p) { +    String *pgcpp_java_type = 0; +    String *jtype = NewString(Getattr(p, "tmap:jtype")); + +    // Strip C comments +    String *stripped_jtype = Swig_strip_c_comments(jtype); +    if (stripped_jtype) { +      Delete(jtype); +      jtype = stripped_jtype; +    } + +    // Remove whitespace +    Replaceall(jtype, " ", ""); +    Replaceall(jtype, "\t", ""); + +    if (Cmp(jtype, "long") == 0) { +      if (proxy_flag) { +	if (!GetFlag(p, "tmap:jtype:nopgcpp") && !nopgcpp_flag) { +	  String *interface_name = getInterfaceName(t, true); +          pgcpp_java_type = interface_name ? interface_name : getProxyName(t); +          if (!pgcpp_java_type) { +            // Look for proxy class parameters passed to C++ layer using non-default typemaps, ie not one of above types +            String *jstype = NewString(Getattr(p, "tmap:jstype")); +            if (jstype) { +              Hash *classes = getClassHash(); +              if (classes) { +                // Strip C comments +                String *stripped_jstype = Swig_strip_c_comments(jstype); +                if (stripped_jstype) { +                  Delete(jstype); +                  jstype = stripped_jstype; +                } +                // Remove whitespace +                Replaceall(jstype, " ", ""); +                Replaceall(jstype, "\t", ""); + +                Iterator ki; +                for (ki = First(classes); ki.key; ki = Next(ki)) { +                  Node *cls = ki.item; +                  if (cls && !Getattr(cls, "feature:ignore")) { +                    String *symname = Getattr(cls, "sym:name"); +                    if (symname && Strcmp(symname, jstype) == 0) { +                      pgcpp_java_type = symname; +                    } +                  } +                } +              } +            } +            Delete(jstype); +          } +	} +      } +    } +    Delete(jtype); +    return pgcpp_java_type; +  } + +  /* ----------------------------------------------------------------------------- +   * outputDirectory() +   * +   * Return the directory to use for generating Java classes/enums and create the +   * subdirectory (does not create if language specific outdir does not exist). +   * ----------------------------------------------------------------------------- */ + +  String *outputDirectory(String *nspace) { +    String *output_directory = Copy(SWIG_output_directory()); +    if (nspace) { +      String *nspace_subdirectory = Copy(nspace); +      Replaceall(nspace_subdirectory, ".", SWIG_FILE_DELIMITER); +      String *newdir_error = Swig_new_subdirectory(output_directory, nspace_subdirectory); +      if (newdir_error) { +	Printf(stderr, "%s\n", newdir_error); +	Delete(newdir_error); +	Exit(EXIT_FAILURE); +      } +      Printv(output_directory, nspace_subdirectory, SWIG_FILE_DELIMITER, 0); +      Delete(nspace_subdirectory); +    } +    return output_directory; +  } + +  /*---------------------------------------------------------------------- +   * Start of director methods +   *--------------------------------------------------------------------*/ + +  /*---------------------------------------------------------------------- +   * getUpcallJNIMethod() +   *--------------------------------------------------------------------*/ + +  String *getUpcallJNIMethod(String *descrip) { +    static struct { +      char code; +      const char *method; +    } upcall_methods[] = { +      { +      'B', "CallStaticByteMethod"}, { +      'C', "CallStaticCharMethod"}, { +      'D', "CallStaticDoubleMethod"}, { +      'F', "CallStaticFloatMethod"}, { +      'I', "CallStaticIntMethod"}, { +      'J', "CallStaticLongMethod"}, { +      'L', "CallStaticObjectMethod"}, { +      'S', "CallStaticShortMethod"}, { +      'V', "CallStaticVoidMethod"}, { +      'Z', "CallStaticBooleanMethod"}, { +      '[', "CallStaticObjectMethod"} +    }; + +    char code; +    int i; + +    code = *Char(descrip); +    for (i = 0; i < (int) (sizeof(upcall_methods) / sizeof(upcall_methods[0])); ++i) +      if (code == upcall_methods[i].code) +	return NewString(upcall_methods[i].method); +    return NULL; +  } + +  /*---------------------------------------------------------------------- +   * emitDirectorUpcalls() +   *--------------------------------------------------------------------*/ + +  void emitDirectorUpcalls() { +    if (n_dmethods) { +      Wrapper *w = NewWrapper(); +      String *jni_imclass_name = makeValidJniName(imclass_name); +      String *swig_module_init = NewString("swig_module_init"); +      String *swig_module_init_jni = makeValidJniName(swig_module_init); +      String *dmethod_data = NewString(""); +      int n_methods = 0; +      Iterator udata_iter; + +      udata_iter = First(dmethods_seq); +      while (udata_iter.item) { +	UpcallData *udata = udata_iter.item; +	Printf(dmethod_data, "  { \"%s\", \"%s\" }", Getattr(udata, "imclass_method"), Getattr(udata, "imclass_fdesc")); +	++n_methods; + +	udata_iter = Next(udata_iter); + +	if (udata_iter.item) +	  Putc(',', dmethod_data); +	Putc('\n', dmethod_data); +      } + +      Printf(f_runtime, "namespace Swig {\n"); +      Printf(f_runtime, "  namespace {\n"); +      Printf(f_runtime, "    jclass jclass_%s = NULL;\n", imclass_name); +      Printf(f_runtime, "    jmethodID director_method_ids[%d];\n", n_methods); +      Printf(f_runtime, "  }\n"); +      Printf(f_runtime, "}\n"); + +      Printf(w->def, "SWIGEXPORT void JNICALL Java_%s%s_%s(JNIEnv *jenv, jclass jcls) {", jnipackage, jni_imclass_name, swig_module_init_jni); +      Printf(w->code, "static struct {\n"); +      Printf(w->code, "  const char *method;\n"); +      Printf(w->code, "  const char *signature;\n"); +      Printf(w->code, "} methods[%d] = {\n", n_methods); +      Printv(w->code, dmethod_data, NIL); +      Printf(w->code, "};\n"); + +      Wrapper_add_local(w, "i", "int i"); + +      Printf(w->code, "Swig::jclass_%s = (jclass) jenv->NewGlobalRef(jcls);\n", imclass_name); +      Printf(w->code, "if (!Swig::jclass_%s) return;\n", imclass_name); +      Printf(w->code, "for (i = 0; i < (int) (sizeof(methods)/sizeof(methods[0])); ++i) {\n"); +      Printf(w->code, "  Swig::director_method_ids[i] = jenv->GetStaticMethodID(jcls, methods[i].method, methods[i].signature);\n"); +      Printf(w->code, "  if (!Swig::director_method_ids[i]) return;\n"); +      Printf(w->code, "}\n"); + +      Printf(w->code, "}\n"); + +      Wrapper_print(w, f_wrappers); +      Delete(dmethod_data); +      Delete(swig_module_init_jni); +      Delete(swig_module_init); +      Delete(jni_imclass_name); +      DelWrapper(w); +    } +  } + +  /*---------------------------------------------------------------------- +   * emitDirectorExtraMethods() +   * +   * This is where the director connect method is generated. +   *--------------------------------------------------------------------*/ +  void emitDirectorExtraMethods(Node *n) { +    if (!Swig_directorclass(n)) +      return; + +    // Output the director connect method: +    String *jni_imclass_name = makeValidJniName(imclass_name); +    String *norm_name = SwigType_namestr(Getattr(n, "name")); +    String *swig_director_connect = Swig_name_member(getNSpace(), getClassPrefix(), "director_connect"); +    String *swig_director_connect_jni = makeValidJniName(swig_director_connect); +    String *smartptr = Getattr(n, "feature:smartptr"); +    String *dirClassName = directorClassName(n); +    Wrapper *code_wrap; + +    Printf(imclass_class_code, "  public final static native void %s(%s obj, long cptr, boolean mem_own, boolean weak_global);\n", +	   swig_director_connect, full_proxy_class_name); + +    code_wrap = NewWrapper(); +    Printf(code_wrap->def, +	   "SWIGEXPORT void JNICALL Java_%s%s_%s(JNIEnv *jenv, jclass jcls, jobject jself, jlong objarg, jboolean jswig_mem_own, " +	   "jboolean jweak_global) {\n", jnipackage, jni_imclass_name, swig_director_connect_jni); + +    if (smartptr) { +      Printf(code_wrap->code, "  %s *obj = *((%s **)&objarg);\n", smartptr, smartptr); +      Printf(code_wrap->code, "  (void)jcls;\n"); +      Printf(code_wrap->code, "  // Keep a local instance of the smart pointer around while we are using the raw pointer\n"); +      Printf(code_wrap->code, "  // Avoids using smart pointer specific API.\n"); +      Printf(code_wrap->code, "  %s *director = static_cast<%s *>(obj->operator->());\n", dirClassName, dirClassName); +    } +    else { +      Printf(code_wrap->code, "  %s *obj = *((%s **)&objarg);\n", norm_name, norm_name); +      Printf(code_wrap->code, "  (void)jcls;\n"); +      Printf(code_wrap->code, "  %s *director = static_cast<%s *>(obj);\n", dirClassName, dirClassName);  +    } + +    Printf(code_wrap->code, "  director->swig_connect_director(jenv, jself, jenv->GetObjectClass(jself), " +	   "(jswig_mem_own == JNI_TRUE), (jweak_global == JNI_TRUE));\n"); +    Printf(code_wrap->code, "}\n"); + +    Wrapper_print(code_wrap, f_wrappers); +    DelWrapper(code_wrap); + +    Delete(swig_director_connect_jni); +    Delete(swig_director_connect); + +    // Output the swigReleaseOwnership, swigTakeOwnership methods: +    String *changeown_method_name = Swig_name_member(getNSpace(), getClassPrefix(), "change_ownership"); +    String *changeown_jnimethod_name = makeValidJniName(changeown_method_name); + +    Printf(imclass_class_code, "  public final static native void %s(%s obj, long cptr, boolean take_or_release);\n", changeown_method_name, full_proxy_class_name); + +    code_wrap = NewWrapper(); +    Printf(code_wrap->def, +	   "SWIGEXPORT void JNICALL Java_%s%s_%s(JNIEnv *jenv, jclass jcls, jobject jself, jlong objarg, jboolean jtake_or_release) {\n", +	   jnipackage, jni_imclass_name, changeown_jnimethod_name); + +    if (Len(smartptr)) { +        Printf(code_wrap->code, "  %s *obj = *((%s **)&objarg);\n", smartptr, smartptr); +        Printf(code_wrap->code, "  // Keep a local instance of the smart pointer around while we are using the raw pointer\n"); +        Printf(code_wrap->code, "  // Avoids using smart pointer specific API.\n"); +        Printf(code_wrap->code, "  %s *director = dynamic_cast<%s *>(obj->operator->());\n", dirClassName, dirClassName); +    } else { +        Printf(code_wrap->code, "  %s *obj = *((%s **)&objarg);\n", norm_name, norm_name); +        Printf(code_wrap->code, "  %s *director = dynamic_cast<%s *>(obj);\n", dirClassName, dirClassName); +    } + +    Printf(code_wrap->code, "  (void)jcls;\n"); +    Printf(code_wrap->code, "  if (director) {\n"); +    Printf(code_wrap->code, "    director->swig_java_change_ownership(jenv, jself, jtake_or_release ? true : false);\n"); +    Printf(code_wrap->code, "  }\n"); +    Printf(code_wrap->code, "}\n"); + +    Wrapper_print(code_wrap, f_wrappers); +    DelWrapper(code_wrap); + +    Delete(changeown_method_name); +    Delete(changeown_jnimethod_name); +    Delete(norm_name); +    Delete(dirClassName); +    Delete(jni_imclass_name); +  } + +  /*---------------------------------------------------------------------- +   * emitCodeTypemap() +   * +   * Output a code typemap that uses $methodname and $jnicall, as used +   * in the directordisconnect, director_release and director_take +   * typemaps. +   *--------------------------------------------------------------------*/ + +  void emitCodeTypemap(Node *n, bool derived, SwigType *lookup_type, const String *typemap, const String *methodname, const String *jnicall) { +    const String *tm = NULL; +    Node *tmattrs = NewHash(); +    String *lookup_tmname = NewString(typemap); +    String *method_attr_name; +    String *method_attr; + +    if (derived) { +      Append(lookup_tmname, "_derived"); +    } + +    tm = typemapLookup(n, lookup_tmname, lookup_type, WARN_NONE, tmattrs); +    method_attr_name = NewStringf("tmap:%s:%s", lookup_tmname, methodname); +    method_attr = Getattr(tmattrs, method_attr_name); + +    if (*Char(tm)) { +      if (method_attr) { +	String *codebody = Copy(tm); +	Replaceall(codebody, "$methodname", method_attr); +	Replaceall(codebody, "$jnicall", jnicall); +	Append(proxy_class_def, codebody); +	Delete(codebody); +      } else { +	Swig_error(input_file, line_number, "No %s method name attribute for %s\n", lookup_tmname, proxy_class_name); +      } +    } else { +      Swig_error(input_file, line_number, "No %s typemap for %s\n", lookup_tmname, proxy_class_name); +    } + +    Delete(tmattrs); +    Delete(lookup_tmname); +    // Delete(method_attr); +  } + +  /* ----------------------------------------------------------------------------- +   * substitutePackagePath() +   * +   * Replace $packagepath using the javapackage typemap associated with passed +   * parm or global package if p is 0. "$packagepath/" is replaced with "" if +   * no package is set. Note that the path separator is a '/'. +   * ----------------------------------------------------------------------------- */ + +  void substitutePackagePath(String *text, Parm *p) { +    String *pkg_path= 0; + +    if (p) +      pkg_path = Swig_typemap_lookup("javapackage", p, "", 0); +    if (!pkg_path || Len(pkg_path) == 0) +      pkg_path = Copy(package_path); + +    if (Len(pkg_path) > 0) { +      Replaceall(pkg_path, ".", "/"); +      Replaceall(text, "$packagepath", pkg_path); +    } else { +      Replaceall(text, "$packagepath/", empty_string); +      Replaceall(text, "$packagepath", empty_string); +    } +    Delete(pkg_path); +  } + +  /* --------------------------------------------------------------- +   * Canonicalize the JNI field descriptor +   * +   * Replace the $packagepath and $javaclassname family of special +   * variables with the desired package and Java proxy name as  +   * required in the JNI field descriptors. +   *  +   * !!SFM!! If $packagepath occurs in the field descriptor, but +   * package_path isn't set (length == 0), then strip it and the +   * optional trailing '/' from the resulting name. +   *  +   * --------------------------------------------------------------- */ + +  String *canonicalizeJNIDescriptor(String *descriptor_in, Parm *p) { +    SwigType *type = Getattr(p, "type"); +    String *descriptor_out = Copy(descriptor_in); + +    substituteClassname(type, descriptor_out, true); +    substitutePackagePath(descriptor_out, p); + +    return descriptor_out; +  } + +  /* --------------------------------------------------------------- +   * classDirectorMethod() +   * +   * Emit a virtual director method to pass a method call on to the  +   * underlying Java object. +   * +   * --------------------------------------------------------------- */ + +  int classDirectorMethod(Node *n, Node *parent, String *super) { +    String *c_classname = Getattr(parent, "name"); +    String *name = Getattr(n, "name"); +    String *symname = Getattr(n, "sym:name"); +    SwigType *returntype = Getattr(n, "type"); +    String *overloaded_name = getOverloadedName(n); +    String *storage = Getattr(n, "storage"); +    String *value = Getattr(n, "value"); +    String *decl = Getattr(n, "decl"); +    String *declaration = NewString(""); +    String *tm; +    Parm *p; +    int i; +    Wrapper *w = NewWrapper(); +    ParmList *l = Getattr(n, "parms"); +    bool is_void = !(Cmp(returntype, "void")); +    String *qualified_return = 0; +    bool pure_virtual = (!(Cmp(storage, "virtual")) && !(Cmp(value, "0"))); +    int status = SWIG_OK; +    bool output_director = true; +    String *dirclassname = directorClassName(parent); +    String *qualified_name = NewStringf("%s::%s", dirclassname, name); +    String *jnidesc = NewString(""); +    String *classdesc = NewString(""); +    String *jniret_desc = NewString(""); +    String *classret_desc = NewString(""); +    SwigType *c_ret_type = NULL; +    String *jupcall_args = NewString("swigjobj"); +    String *imclass_dmethod; +    String *callback_def = NewString(""); +    String *callback_code = NewString(""); +    String *imcall_args = NewString(""); +    int classmeth_off = curr_class_dmethod - first_class_dmethod; +    bool ignored_method = GetFlag(n, "feature:ignore") ? true : false; +    String *qualified_classname = getProxyName(getClassName()); + +    // Kludge Alert: functionWrapper sets sym:overload properly, but it +    // isn't at this point, so we have to manufacture it ourselves. At least +    // we're consistent with the sym:overload name in functionWrapper. (?? when +    // does the overloaded method name get set?) + +    imclass_dmethod = NewStringf("%s", Swig_name_member(getNSpace(), dirclassname, overloaded_name)); + +    qualified_return = SwigType_rcaststr(returntype, "c_result"); + +    if (!is_void && (!ignored_method || pure_virtual)) { +      if (!SwigType_isclass(returntype)) { +	if (!(SwigType_ispointer(returntype) || SwigType_isreference(returntype))) { +	  String *construct_result = NewStringf("= SwigValueInit< %s >()", SwigType_lstr(returntype, 0)); +	  Wrapper_add_localv(w, "c_result", SwigType_lstr(returntype, "c_result"), construct_result, NIL); +	  Delete(construct_result); +	} else { +	  String *base_typename = SwigType_base(returntype); +	  String *resolved_typename = SwigType_typedef_resolve_all(base_typename); +	  Symtab *symtab = Getattr(n, "sym:symtab"); +	  Node *typenode = Swig_symbol_clookup(resolved_typename, symtab); + +	  if (SwigType_ispointer(returntype) || (typenode && Getattr(typenode, "abstracts"))) { +	    /* initialize pointers to something sane. Same for abstract +	       classes when a reference is returned. */ +	    Wrapper_add_localv(w, "c_result", SwigType_lstr(returntype, "c_result"), "= 0", NIL); +	  } else { +	    /* If returning a reference, initialize the pointer to a sane +	       default - if a Java exception occurs, then the pointer returns +	       something other than a NULL-initialized reference. */ +	    SwigType *noref_type = SwigType_del_reference(Copy(returntype)); +	    String *noref_ltype = SwigType_lstr(noref_type, 0); +	    String *return_ltype = SwigType_lstr(returntype, 0); + +	    Wrapper_add_localv(w, "result_default", "static", noref_ltype, "result_default", NIL); +	    Wrapper_add_localv(w, "c_result", return_ltype, "c_result", NIL); +	    Printf(w->code, "result_default = SwigValueInit< %s >();\n", noref_ltype); +	    Printf(w->code, "c_result = &result_default;\n"); +	    Delete(return_ltype); +	    Delete(noref_ltype); +	    Delete(noref_type); +	  } + +	  Delete(base_typename); +	  Delete(resolved_typename); +	} +      } else { +	SwigType *vt; + +	vt = cplus_value_type(returntype); +	if (!vt) { +	  Wrapper_add_localv(w, "c_result", SwigType_lstr(returntype, "c_result"), NIL); +	} else { +	  Wrapper_add_localv(w, "c_result", SwigType_lstr(vt, "c_result"), NIL); +	  Delete(vt); +	} +      } +    } + +    /* Create the intermediate class wrapper */ +    tm = Swig_typemap_lookup("jtype", n, "", 0); +    if (tm) { +      Printf(callback_def, "  public static %s %s(%s jself", tm, imclass_dmethod, qualified_classname); +    } else { +      Swig_warning(WARN_JAVA_TYPEMAP_JTYPE_UNDEF, input_file, line_number, "No jtype typemap defined for %s\n", SwigType_str(returntype, 0)); +    } + +    String *cdesc = NULL; +    SwigType *covariant = Getattr(n, "covariant"); +    SwigType *adjustedreturntype = covariant ? covariant : returntype; +    Parm *adjustedreturntypeparm = NewParmNode(adjustedreturntype, n); + +    if (Swig_typemap_lookup("directorin", adjustedreturntypeparm, "", 0) +	&& (cdesc = Getattr(adjustedreturntypeparm, "tmap:directorin:descriptor"))) { + +      // Note that in the case of polymorphic (covariant) return types, the +      // method's return type is changed to be the base of the C++ return +      // type +      String *jnidesc_canon = canonicalizeJNIDescriptor(cdesc, adjustedreturntypeparm); +      Append(classret_desc, jnidesc_canon); +      Delete(jnidesc_canon); +    } else { +      Swig_warning(WARN_TYPEMAP_DIRECTORIN_UNDEF, input_file, line_number, "No or improper directorin typemap defined for %s for use in %s::%s (skipping director method)\n",  +	  SwigType_str(returntype, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); +      output_director = false; +    } + +    /* Get the JNI field descriptor for this return type, add the JNI field descriptor +       to jniret_desc */ +    if ((c_ret_type = Swig_typemap_lookup("jni", n, "", 0))) { +      Parm *tp = NewParmNode(c_ret_type, n); + +      if (!is_void && !ignored_method) { +	String *jretval_decl = NewStringf("%s jresult", c_ret_type); +	Wrapper_add_localv(w, "jresult", jretval_decl, "= 0", NIL); +	Delete(jretval_decl); +      } + +      String *jdesc = NULL; +      if (Swig_typemap_lookup("directorin", tp, "", 0) +	  && (jdesc = Getattr(tp, "tmap:directorin:descriptor"))) { + +	// Objects marshalled passing a Java class across JNI boundary use jobject - the nouse flag indicates this +	// We need the specific Java class name instead of the generic 'Ljava/lang/Object;' +	if (GetFlag(tp, "tmap:directorin:nouse")) +	  jdesc = cdesc; +	String *jnidesc_canon = canonicalizeJNIDescriptor(jdesc, tp); +	Append(jniret_desc, jnidesc_canon); +	Delete(jnidesc_canon); +      } else { +	Swig_warning(WARN_TYPEMAP_DIRECTORIN_UNDEF, input_file, line_number, +		     "No or improper directorin typemap defined for %s for use in %s::%s (skipping director method)\n",  +		     SwigType_str(c_ret_type, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); +	output_director = false; +      } + +      Delete(tp); +    } else { +      Swig_warning(WARN_JAVA_TYPEMAP_JNI_UNDEF, input_file, line_number, "No jni typemap defined for %s for use in %s::%s (skipping director method)\n",  +	  SwigType_str(returntype, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); +      output_director = false; +    } + +    Delete(adjustedreturntypeparm); + +    Swig_director_parms_fixup(l); + +    /* Attach the standard typemaps */ +    Swig_typemap_attach_parms("out", l, 0); +    Swig_typemap_attach_parms("jni", l, 0); +    Swig_typemap_attach_parms("jtype", l, 0); +    Swig_typemap_attach_parms("directorin", l, w); +    Swig_typemap_attach_parms("javadirectorin", l, 0); +    Swig_typemap_attach_parms("directorargout", l, w); + +    if (!ignored_method) { +      /* Add Java environment pointer to wrapper */ +      String *jenvstr = NewString("jenv"); +      String *jobjstr = NewString("swigjobj"); + +      Wrapper_add_localv(w, "swigjnienv", "JNIEnvWrapper", "swigjnienv(this)", NIL, NIL); +      Wrapper_add_localv(w, jenvstr, "JNIEnv *", jenvstr, "= swigjnienv.getJNIEnv()", NIL); +      Wrapper_add_localv(w, jobjstr, "jobject", jobjstr, "= (jobject) NULL", NIL); +      Delete(jenvstr); +      Delete(jobjstr); + +      /* Preamble code */ +      Printf(w->code, "if (!swig_override[%d]) {\n", classmeth_off); +    } + +    if (!pure_virtual) { +      String *super_call = Swig_method_call(super, l); +      if (is_void) { +	Printf(w->code, "%s;\n", super_call); +	if (!ignored_method) +	  Printf(w->code, "return;\n"); +      } else { +	Printf(w->code, "return %s;\n", super_call); +      } +      Delete(super_call); +    } else { +      Printf(w->code, "SWIG_JavaThrowException(JNIEnvWrapper(this).getJNIEnv(), SWIG_JavaDirectorPureVirtual, "); +      Printf(w->code, "\"Attempted to invoke pure virtual method %s::%s.\");\n", SwigType_namestr(c_classname), SwigType_namestr(name)); + +      /* Make sure that we return something in the case of a pure +       * virtual method call for syntactical reasons. */ +      if (!is_void) +	Printf(w->code, "return %s;", qualified_return); +      else if (!ignored_method) +	Printf(w->code, "return;\n"); +    } + +    if (!ignored_method) { +      Printf(w->code, "}\n"); +      Printf(w->code, "swigjobj = swig_get_self(jenv);\n"); +      Printf(w->code, "if (swigjobj && jenv->IsSameObject(swigjobj, NULL) == JNI_FALSE) {\n"); +    } + +    /* Start the Java field descriptor for the intermediate class's upcall (insert jself object) */ +    Parm *tp = NewParmNode(c_classname, n); +    String *jdesc; + +    if ((tm = Swig_typemap_lookup("directorin", tp, "", 0)) +	&& (jdesc = Getattr(tp, "tmap:directorin:descriptor"))) { +      String *jni_canon = canonicalizeJNIDescriptor(jdesc, tp); +      Append(jnidesc, jni_canon); +      Delete(jni_canon); +      Delete(tm); +    } else { +      Swig_warning(WARN_TYPEMAP_DIRECTORIN_UNDEF, input_file, line_number, +		   "No or improper directorin typemap for type %s  for use in %s::%s (skipping director method)\n",  +		   SwigType_str(returntype, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); +      output_director = false; +    } + +    Delete(tp); + +    /* Go through argument list, convert from native to Java */ +    for (i = 0, p = l; p; ++i) { +      /* Is this superfluous? */ +      while (checkAttribute(p, "tmap:directorin:numinputs", "0")) { +	p = Getattr(p, "tmap:directorin:next"); +      } + +      SwigType *pt = Getattr(p, "type"); +      String *ln = makeParameterName(n, p, i, false); +      String *c_param_type = NULL; +      String *c_decl = NewString(""); +      String *arg = NewString(""); + +      Printf(arg, "j%s", ln); + +      /* Add various typemap's 'throws' clauses */ +      addThrows(n, "tmap:directorin", p); +      addThrows(n, "tmap:out", p); + +      /* And add to the upcall args */ +      Printf(jupcall_args, ", %s", arg); + +      /* Get parameter's intermediary C type */ +      if ((c_param_type = Getattr(p, "tmap:jni"))) { +	Parm *tp = NewParm(c_param_type, Getattr(p, "name"), n); +	String *desc_tm = NULL, *jdesc = NULL, *cdesc = NULL; + +	/* Add to local variables */ +	Printf(c_decl, "%s %s", c_param_type, arg); +	if (!ignored_method) +	  Wrapper_add_localv(w, arg, c_decl, (!(SwigType_ispointer(pt) || SwigType_isreference(pt)) ? "" : "= 0"), NIL); + +	/* Add input marshalling code and update JNI field descriptor */ +	if ((desc_tm = Swig_typemap_lookup("directorin", tp, "", 0)) +	    && (jdesc = Getattr(tp, "tmap:directorin:descriptor")) +	    && (tm = Getattr(p, "tmap:directorin")) +	    && (cdesc = Getattr(p, "tmap:directorin:descriptor"))) { + +	  // Objects marshalled by passing a Java class across the JNI boundary use jobject as the JNI type -  +	  // the nouse flag indicates this. We need the specific Java class name instead of the generic 'Ljava/lang/Object;' +	  if (GetFlag(tp, "tmap:directorin:nouse")) +	    jdesc = cdesc; +	  String *jni_canon = canonicalizeJNIDescriptor(jdesc, tp); +	  Append(jnidesc, jni_canon); +	  Delete(jni_canon); + +	  Setattr(p, "emit:directorinput", arg); +	  Replaceall(tm, "$input", arg); +	  Replaceall(tm, "$owner", "0"); + +	  if (Len(tm)) +	    if (!ignored_method) +	      Printf(w->code, "%s\n", tm); + +	  /* Add parameter to the intermediate class code if generating the +	   * intermediate's upcall code */ +	  if ((tm = Getattr(p, "tmap:jtype"))) { +	    String *din = Copy(Getattr(p, "tmap:javadirectorin")); +            addThrows(n, "tmap:javadirectorin", p); + +	    if (din) { +	      Replaceall(din, "$module", module_class_name); +	      Replaceall(din, "$imclassname", imclass_name); +	      substituteClassname(pt, din); +	      Replaceall(din, "$jniinput", ln); + +	      if (i > 0) +		Printf(imcall_args, ", "); +	      Printf(callback_def, ", %s %s", tm, ln); + +	      if (Cmp(din, ln)) { +		Printv(imcall_args, din, NIL); +	      } else +		Printv(imcall_args, ln, NIL); + +	      jni_canon = canonicalizeJNIDescriptor(cdesc, p); +	      Append(classdesc, jni_canon); +	      Delete(jni_canon); +	    } else { +	      Swig_warning(WARN_JAVA_TYPEMAP_JAVADIRECTORIN_UNDEF, input_file, line_number, "No javadirectorin typemap defined for %s for use in %s::%s (skipping director method)\n",  +		  SwigType_str(pt, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); +	      output_director = false; +	    } +	  } else { +	    Swig_warning(WARN_JAVA_TYPEMAP_JTYPE_UNDEF, input_file, line_number, "No jtype typemap defined for %s for use in %s::%s (skipping director method)\n",  +		SwigType_str(pt, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); +	    output_director = false; +	  } + +	  p = Getattr(p, "tmap:directorin:next"); + +	  Delete(desc_tm); +	} else { +	  if (!desc_tm) { +	    Swig_warning(WARN_JAVA_TYPEMAP_JAVADIRECTORIN_UNDEF, input_file, line_number, +			 "No or improper directorin typemap defined for %s for use in %s::%s (skipping director method)\n",  +			 SwigType_str(c_param_type, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); +	    p = nextSibling(p); +	  } else if (!jdesc) { +	    Swig_warning(WARN_JAVA_TYPEMAP_DIRECTORIN_NODESC, input_file, line_number, +			 "Missing JNI descriptor in directorin typemap defined for %s for use in %s::%s (skipping director method)\n",  +			 SwigType_str(c_param_type, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); +	    p = Getattr(p, "tmap:directorin:next"); +	  } else if (!tm) { +	    Swig_warning(WARN_JAVA_TYPEMAP_JAVADIRECTORIN_UNDEF, input_file, line_number, +			 "No or improper directorin typemap defined for argument %s for use in %s::%s (skipping director method)\n",  +			 SwigType_str(pt, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); +	    p = nextSibling(p); +	  } else if (!cdesc) { +	    Swig_warning(WARN_JAVA_TYPEMAP_DIRECTORIN_NODESC, input_file, line_number, +			 "Missing JNI descriptor in directorin typemap defined for %s for use in %s::%s (skipping director method)\n",  +			 SwigType_str(pt, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); +	    p = Getattr(p, "tmap:directorin:next"); +	  } + +	  output_director = false; +	} + +      } else { +	Swig_warning(WARN_JAVA_TYPEMAP_JNI_UNDEF, input_file, line_number, "No jni typemap defined for %s for use in %s::%s (skipping director method)\n",  +	    SwigType_str(pt, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); +	output_director = false; +	p = nextSibling(p); +      } + +      Delete(arg); +      Delete(c_decl); +      Delete(ln); +    } + +    /* header declaration, start wrapper definition */ +    String *target; +    SwigType *rtype = Getattr(n, "conversion_operator") ? 0 : Getattr(n, "classDirectorMethods:type"); +    target = Swig_method_decl(rtype, decl, qualified_name, l, 0); +    Printf(w->def, "%s", target); +    Delete(qualified_name); +    Delete(target); +    target = Swig_method_decl(rtype, decl, name, l, 1); +    Printf(declaration, "    virtual %s", target); +    Delete(target); + +    // Add any exception specifications to the methods in the director class +    // Get any Java exception classes in the throws typemap +    ParmList *throw_parm_list = NULL; + +    // May need to add Java throws clause to director methods if %catches defined +    // Get any Java exception classes in the throws typemap +    ParmList *catches_list = Getattr(n, "catchlist"); +    if (catches_list) { +      Swig_typemap_attach_parms("throws", catches_list, 0); +      Swig_typemap_attach_parms("directorthrows", catches_list, 0); +      for (p = catches_list; p; p = nextSibling(p)) { +	addThrows(n, "tmap:throws", p); +      } +    } + +    if (Getattr(n, "noexcept")) { +      Append(w->def, " noexcept"); +      Append(declaration, " noexcept"); +    } +    if ((throw_parm_list = Getattr(n, "throws")) || Getattr(n, "throw")) { +      int gencomma = 0; + +      Append(w->def, " throw("); +      Append(declaration, " throw("); + +      if (throw_parm_list) { +	Swig_typemap_attach_parms("throws", throw_parm_list, 0); +	Swig_typemap_attach_parms("directorthrows", throw_parm_list, 0); +      } +      for (p = throw_parm_list; p; p = nextSibling(p)) { +	if (Getattr(p, "tmap:throws")) { +	  // %catches replaces the specified exception specification +	  if (!catches_list) { +	    addThrows(n, "tmap:throws", p); +	  } + +	  if (gencomma++) { +	    Append(w->def, ", "); +	    Append(declaration, ", "); +	  } + +	  Printf(w->def, "%s", SwigType_str(Getattr(p, "type"), 0)); +	  Printf(declaration, "%s", SwigType_str(Getattr(p, "type"), 0)); +	} +      } + +      Append(w->def, ")"); +      Append(declaration, ")"); +    } + +    Append(w->def, " {"); +    Append(declaration, ";\n"); + +    /* Emit the intermediate class's upcall to the actual class */ + +    String *upcall = NewStringf("jself.%s(%s)", symname, imcall_args); + +    // Handle exception classes specified in the "except" feature's "throws" attribute +    addThrows(n, "feature:except", n); + +    if (!is_void) { +      if ((tm = Swig_typemap_lookup("javadirectorout", n, "", 0))) { +        addThrows(n, "tmap:javadirectorout", n); +	substituteClassname(returntype, tm); +	Replaceall(tm, "$javacall", upcall); + +	Printf(callback_code, "    return %s;\n", tm); +      } + +      if ((tm = Swig_typemap_lookup("out", n, "", 0))) +        addThrows(n, "tmap:out", n); + +      Delete(tm); +    } else +      Printf(callback_code, "    %s;\n", upcall); + +    Printf(callback_code, "  }\n"); +    Delete(upcall); + +    /* Finish off the inherited upcall's definition */ +    Putc(')', callback_def); +    generateThrowsClause(n, callback_def); +    Printf(callback_def, " {\n"); + +    if (!ignored_method) { +      /* Emit the actual upcall through */ +      String *imclass_desc = NewStringf("(%s)%s", jnidesc, jniret_desc); +      String *class_desc = NewStringf("(%s)%s", classdesc, classret_desc); +      UpcallData *udata = addUpcallMethod(imclass_dmethod, symname, imclass_desc, class_desc, decl); +      String *methid = Getattr(udata, "imclass_methodidx"); +      String *methop = getUpcallJNIMethod(jniret_desc); + +      if (!is_void) +	Printf(w->code, "jresult = (%s) ", c_ret_type); + +      Printf(w->code, "jenv->%s(Swig::jclass_%s, Swig::director_method_ids[%s], %s);\n", methop, imclass_name, methid, jupcall_args); + +      // Generate code to handle any Java exception thrown by director delegation +      directorExceptHandler(n, catches_list ? catches_list : throw_parm_list, w); + +      if (!is_void) { +	String *jresult_str = NewString("jresult"); +	String *result_str = NewString("c_result"); + +	/* Copy jresult into c_result... */ +	if ((tm = Swig_typemap_lookup("directorout", n, result_str, w))) { +	  addThrows(n, "tmap:directorout", n); +	  Replaceall(tm, "$input", jresult_str); +	  Replaceall(tm, "$result", result_str); +	  Printf(w->code, "%s\n", tm); +	} else { +	  Swig_warning(WARN_TYPEMAP_DIRECTOROUT_UNDEF, input_file, line_number, +		       "Unable to use return type %s used in %s::%s (skipping director method)\n",  +		       SwigType_str(returntype, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); +	  output_director = false; +	} + +	Delete(jresult_str); +	Delete(result_str); +      } + +      /* Marshal outputs */ +      for (p = l; p;) { +	if ((tm = Getattr(p, "tmap:directorargout"))) { +	  addThrows(n, "tmap:directorargout", p); +	  Replaceall(tm, "$result", makeParameterName(n, p, i, false)); +	  Replaceall(tm, "$input", Getattr(p, "emit:directorinput")); +	  Printv(w->code, tm, "\n", NIL); +	  p = Getattr(p, "tmap:directorargout:next"); +	} else { +	  p = nextSibling(p); +	} +      } + +      Delete(imclass_desc); +      Delete(class_desc); + +      /* Terminate wrapper code */ +      Printf(w->code, "} else {\n"); +      Printf(w->code, "SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, \"null upcall object in %s::%s \");\n", +	     SwigType_namestr(c_classname), SwigType_namestr(name)); +      Printf(w->code, "}\n"); + +      Printf(w->code, "if (swigjobj) jenv->DeleteLocalRef(swigjobj);\n"); + +      if (!is_void) +	Printf(w->code, "return %s;", qualified_return); +    } + +    Printf(w->code, "}"); + +    // We expose virtual protected methods via an extra public inline method which makes a straight call to the wrapped class' method +    String *inline_extra_method = NewString(""); +    if (dirprot_mode() && !is_public(n) && !pure_virtual) { +      Printv(inline_extra_method, declaration, NIL); +      String *extra_method_name = NewStringf("%sSwigPublic", name); +      Replaceall(inline_extra_method, name, extra_method_name); +      Replaceall(inline_extra_method, ";\n", " {\n      "); +      if (!is_void) +	Printf(inline_extra_method, "return "); +      String *methodcall = Swig_method_call(super, l); +      Printv(inline_extra_method, methodcall, ";\n    }\n", NIL); +      Delete(methodcall); +      Delete(extra_method_name); +    } + +    /* emit the director method */ +    if (status == SWIG_OK && output_director) { +      if (!is_void) { +	Replaceall(w->code, "$null", qualified_return); +      } else { +	Replaceall(w->code, "$null", ""); +      } +      if (!GetFlag(n, "feature:ignore")) +	Printv(imclass_directors, callback_def, callback_code, NIL); +      if (!Getattr(n, "defaultargs")) { +	Replaceall(w->code, "$symname", symname); +	Wrapper_print(w, f_directors); +	Printv(f_directors_h, declaration, NIL); +	Printv(f_directors_h, inline_extra_method, NIL); +      } +    } + +    Delete(inline_extra_method); +    Delete(qualified_return); +    Delete(jnidesc); +    Delete(c_ret_type); +    Delete(jniret_desc); +    Delete(declaration); +    Delete(callback_def); +    Delete(callback_code); +    DelWrapper(w); + +    return status; +  } + +  /* ------------------------------------------------------------ +   * directorExceptHandler() +   * +   * Emit code to map Java exceptions back to C++ exceptions when +   * feature("director:except") is applied to a method node. +   * This is generated after the Java method upcall. +   * ------------------------------------------------------------ */ + +  void directorExceptHandler(Node *n, ParmList *throw_parm_list, Wrapper *w) { + +    String *directorexcept = Getattr(n, "feature:director:except"); +    if (!directorexcept) { +      directorexcept = NewString(""); +      Printf(directorexcept, "jthrowable $error = jenv->ExceptionOccurred();\n"); +      Printf(directorexcept, "if ($error) {"); +      Printf(directorexcept, "$directorthrowshandlers\n"); +      Printf(directorexcept, "  Swig::DirectorException::raise(jenv, $error);\n"); +      Printf(directorexcept, "}\n"); +    } else { +      directorexcept = Copy(directorexcept); +    } + +    // Can explicitly disable director:except by setting to "" or "0" +    if (Len(directorexcept) > 0 && Cmp(directorexcept, "0") != 0) { + +      // Replace $packagepath +      substitutePackagePath(directorexcept, 0); + +      // Replace $directorthrowshandlers with any defined typemap handlers (or nothing) +      if (Strstr(directorexcept, "$directorthrowshandlers")) { +	String *directorthrowshandlers_code = NewString(""); + +	for (Parm *p = throw_parm_list; p; p = nextSibling(p)) { +	  String *tm = Getattr(p, "tmap:directorthrows"); + +	  if (tm) { +	    // replace $packagepath/$javaclassname +	    String *directorthrows = canonicalizeJNIDescriptor(tm, p); +	    Printv(directorthrowshandlers_code, directorthrows, NIL); +	    Delete(directorthrows); +	  } else { +	    String *t = Getattr(p,"type"); +	    Swig_warning(WARN_TYPEMAP_DIRECTORTHROWS_UNDEF, Getfile(n), Getline(n), "No directorthrows typemap defined for %s\n", SwigType_str(t, 0)); +	  } +	} +	Replaceall(directorexcept, "$directorthrowshandlers", directorthrowshandlers_code); +	Delete(directorthrowshandlers_code); +      } + +      Replaceall(directorexcept, "$error", "swigerror"); +      Printf(w->code, "    %s\n", directorexcept); +    } +    Delete(directorexcept); +  } + +  /* ------------------------------------------------------------ +   * directorPrefixArgs() +   * ------------------------------------------------------------ */ + +  void directorPrefixArgs(Node *n) { +    Parm *p; + +    /* Need to prepend 'jenv' to the director constructor's argument list */ + +    String *jenv_type = NewString("JNIEnv"); + +    SwigType_add_pointer(jenv_type); + +    p = NewParm(jenv_type, NewString("jenv"), n); +    Setattr(p, "arg:byname", "1"); +    set_nextSibling(p, NULL); + +    Setattr(n, "director:prefix_args", p); +  } + +  /* ------------------------------------------------------------ +   * classDirectorConstructor() +   * ------------------------------------------------------------ */ + +  int classDirectorConstructor(Node *n) { +    Node *parent = parentNode(n); +    String *decl = Getattr(n, "decl"); +    String *supername = Swig_class_name(parent); +    String *dirclassname = directorClassName(parent); +    String *sub = NewString(""); +    Parm *p; +    ParmList *superparms = Getattr(n, "parms"); +    ParmList *parms; +    int argidx = 0; + +    /* Assign arguments to superclass's parameters, if not already done */ +    for (p = superparms; p; p = nextSibling(p)) { +      String *pname = Getattr(p, "name"); + +      if (!pname) { +	pname = NewStringf("arg%d", argidx++); +	Setattr(p, "name", pname); +      } +    } + +    /* insert jenv prefix argument */ +    parms = CopyParmList(superparms); + +    String *jenv_type = NewString("JNIEnv"); +    SwigType_add_pointer(jenv_type); +    p = NewParm(jenv_type, NewString("jenv"), n); +    set_nextSibling(p, parms); +    parms = p; + +    directorPrefixArgs(n); + +    if (!Getattr(n, "defaultargs")) { +      /* constructor */ +      { +	String *basetype = Getattr(parent, "classtype"); +	String *target = Swig_method_decl(0, decl, dirclassname, parms, 0); +	String *call = Swig_csuperclass_call(0, basetype, superparms); +	String *classtype = SwigType_namestr(Getattr(n, "name")); + +	Printf(f_directors, "%s::%s : %s, %s {\n", dirclassname, target, call, Getattr(parent, "director:ctor")); +	Printf(f_directors, "}\n\n"); + +	Delete(classtype); +	Delete(target); +	Delete(call); +      } + +      /* constructor header */ +      { +	String *target = Swig_method_decl(0, decl, dirclassname, parms, 1); +	Printf(f_directors_h, "    %s;\n", target); +	Delete(target); +      } +    } + +    Delete(sub); +    Delete(supername); +    Delete(jenv_type); +    Delete(parms); +    Delete(dirclassname); +    return Language::classDirectorConstructor(n); +  } + +  /* ------------------------------------------------------------ +   * classDirectorDefaultConstructor() +   * ------------------------------------------------------------ */ + +  int classDirectorDefaultConstructor(Node *n) { +    String *classname = Swig_class_name(n); +    String *classtype = SwigType_namestr(Getattr(n, "name")); +    String *dirClassName = directorClassName(n); +    Wrapper *w = NewWrapper(); + +    Printf(w->def, "%s::%s(JNIEnv *jenv) : %s {", dirClassName, dirClassName, Getattr(n, "director:ctor")); +    Printf(w->code, "}\n"); +    Wrapper_print(w, f_directors); + +    Printf(f_directors_h, "    %s(JNIEnv *jenv);\n", dirClassName); +    DelWrapper(w); +    Delete(classtype); +    Delete(classname); +    Delete(dirClassName); +    directorPrefixArgs(n); +    return Language::classDirectorDefaultConstructor(n); +  } + + +  /* ------------------------------------------------------------ +   * classDirectorInit() +   * ------------------------------------------------------------ */ + +  int classDirectorInit(Node *n) { +    Delete(none_comparison); +    none_comparison = NewString("");	// not used + +    Delete(director_ctor_code); +    director_ctor_code = NewString("$director_new"); + +    directorDeclaration(n); + +    Printf(f_directors_h, "%s {\n", Getattr(n, "director:decl")); +    Printf(f_directors_h, "\npublic:\n"); +    Printf(f_directors_h, "    void swig_connect_director(JNIEnv *jenv, jobject jself, jclass jcls, bool swig_mem_own, bool weak_global);\n"); + +    /* Keep track of the director methods for this class */ +    first_class_dmethod = curr_class_dmethod = n_dmethods; + +    return Language::classDirectorInit(n); +  } + +  /* ---------------------------------------------------------------------- +   * classDirectorDestructor() +   * ---------------------------------------------------------------------- */ + +  int classDirectorDestructor(Node *n) { +    Node *current_class = getCurrentClass(); +    String *full_classname = Getattr(current_class, "name"); +    String *classname = Swig_class_name(current_class); +    String *dirClassName = directorClassName(current_class); +    Wrapper *w = NewWrapper(); + +    if (Getattr(n, "noexcept")) { +      Printf(f_directors_h, "    virtual ~%s() noexcept;\n", dirClassName); +      Printf(w->def, "%s::~%s() noexcept {\n", dirClassName, dirClassName); +    } else if (Getattr(n, "throw")) { +      Printf(f_directors_h, "    virtual ~%s() throw();\n", dirClassName); +      Printf(w->def, "%s::~%s() throw() {\n", dirClassName, dirClassName); +    } else { +      Printf(f_directors_h, "    virtual ~%s();\n", dirClassName); +      Printf(w->def, "%s::~%s() {\n", dirClassName, dirClassName); +    } + +    /* Ensure that correct directordisconnect typemap's method name is called +     * here: */ + +    Node *disconn_attr = NewHash(); +    String *disconn_methodname = NULL; + +    typemapLookup(n, "directordisconnect", full_classname, WARN_NONE, disconn_attr); +    disconn_methodname = Getattr(disconn_attr, "tmap:directordisconnect:methodname"); + +    Printv(w->code, "  swig_disconnect_director_self(\"", disconn_methodname, "\");\n", "}\n", NIL); + +    Wrapper_print(w, f_directors); + +    DelWrapper(w); +    Delete(disconn_attr); +    Delete(classname); +    Delete(dirClassName); +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * classDirectorEnd() +   * ------------------------------------------------------------ */ + +  int classDirectorEnd(Node *n) { +    String *full_classname = Getattr(n, "name"); +    String *classname = getProxyName(full_classname, true); +    String *director_classname = directorClassName(n); +    String *internal_classname; + +    Wrapper *w = NewWrapper(); + +    if (Len(package_path) > 0) +      internal_classname = NewStringf("%s/%s", package_path, classname); +    else +      internal_classname = NewStringf("%s", classname); + +    // If the namespace is multiple levels, the result of getNSpace() will have inserted +    // .'s to delimit namespaces, so we need to replace those with /'s +    Replace(internal_classname, NSPACE_SEPARATOR, "/", DOH_REPLACE_ANY); + +    Printf(w->def, "void %s::swig_connect_director(JNIEnv *jenv, jobject jself, jclass jcls, bool swig_mem_own, bool weak_global) {", director_classname); + +    Printf(w->def, "static jclass baseclass = swig_new_global_ref(jenv, \"%s\");\n", internal_classname); +    Printf(w->def, "if (!baseclass) return;\n"); + +    if (first_class_dmethod != curr_class_dmethod) { +      Printf(w->def, "static SwigDirectorMethod methods[] = {\n"); + +      for (int i = first_class_dmethod; i < curr_class_dmethod; ++i) { +	UpcallData *udata = Getitem(dmethods_seq, i); + +	Printf(w->def, "SwigDirectorMethod(jenv, baseclass, \"%s\", \"%s\")", Getattr(udata, "method"), Getattr(udata, "fdesc")); +	if (i != curr_class_dmethod - 1) +	  Putc(',', w->def); +	Putc('\n', w->def); +      } + +      Printf(w->def, "};"); +    } + +    Printf(w->code, "if (swig_set_self(jenv, jself, swig_mem_own, weak_global)) {\n"); + +    int n_methods = curr_class_dmethod - first_class_dmethod; + +    if (n_methods) { +      /* Emit the swig_overrides() method and the swig_override array */ +      Printf(f_directors_h, "public:\n"); +      Printf(f_directors_h, "    bool swig_overrides(int n) {\n"); +      Printf(f_directors_h, "      return (n < %d ? swig_override[n] : false);\n", n_methods); +      Printf(f_directors_h, "    }\n"); +      Printf(f_directors_h, "protected:\n"); +      Printf(f_directors_h, "    Swig::BoolArray<%d> swig_override;\n", n_methods); + +      /* Emit the code to look up the class's methods, initialize the override array */ + +      Printf(w->code, "  bool derived = (jenv->IsSameObject(baseclass, jcls) ? false : true);\n"); +      Printf(w->code, "  for (int i = 0; i < %d; ++i) {\n", n_methods); +      // Generally, derived classes have a mix of overridden and +      // non-overridden methods and it is worth making a GetMethodID +      // check during initialization to determine if each method is +      // overridden, thus avoiding unnecessary calls into Java. +      // +      // On the other hand, when derived classes are +      // expected to override all director methods then the +      // GetMethodID calls are inefficient, and it is better to let +      // the director unconditionally call up into Java.  The resulting code +      // will still behave correctly (though less efficiently) when Java +      // code doesn't override a given method. +      // +      // The assumeoverride feature on a director controls whether or not +      // overrides are assumed. +      if (GetFlag(n, "feature:director:assumeoverride")) { +        Printf(w->code, "  swig_override[i] = derived;\n"); +      } else { +        Printf(w->code, "  swig_override[i] = false;\n"); +        Printf(w->code, "  if (derived) {\n"); +        Printf(w->code, "    jmethodID methid = jenv->GetMethodID(jcls, methods[i].name, methods[i].desc);\n"); +        Printf(w->code, "    swig_override[i] = methods[i].methid && (methid != methods[i].methid);\n"); +        Printf(w->code, "    jenv->ExceptionClear();\n"); +        Printf(w->code, "  }\n"); +      } +      Printf(w->code, "}\n"); +    } else { +      Printf(f_directors_h, "public:\n"); +      Printf(f_directors_h, "    bool swig_overrides(int n) {\n"); +      Printf(f_directors_h, "      return false;\n"); +      Printf(f_directors_h, "    }\n"); +    } + +    Printf(f_directors_h, "};\n\n"); +    Printf(w->code, "}\n"); +    Printf(w->code, "}\n"); + +    Wrapper_print(w, f_directors); + +    DelWrapper(w); +    Delete(internal_classname); + +    return Language::classDirectorEnd(n); +  } + +  /* -------------------------------------------------------------------- +   * classDirectorDisown() +   * ------------------------------------------------------------------*/ + +  virtual int classDirectorDisown(Node *n) { +    (void) n; +    return SWIG_OK; +  } + +  /*---------------------------------------------------------------------- +   * extraDirectorProtectedCPPMethodsRequired() +   *--------------------------------------------------------------------*/ + +  bool extraDirectorProtectedCPPMethodsRequired() const { +    return false; +  } + +  /*---------------------------------------------------------------------- +   * directorDeclaration() +   * +   * Generate the director class's declaration +   * e.g. "class SwigDirector_myclass : public myclass, public Swig::Director {" +   *--------------------------------------------------------------------*/ + +  void directorDeclaration(Node *n) { +    String *base = Getattr(n, "classtype"); +    String *class_ctor = NewString("Swig::Director(jenv)"); + +    String *directorname = directorClassName(n); +    String *declaration = Swig_class_declaration(n, directorname); + +    Printf(declaration, " : public %s, public Swig::Director", base); + +    // Stash stuff for later. +    Setattr(n, "director:decl", declaration); +    Setattr(n, "director:ctor", class_ctor); +  } + +  /*---------------------------------------------------------------------- +   * nestedClassesSupport() +   *--------------------------------------------------------------------*/ + +  NestedClassSupport nestedClassesSupport() const { +    return NCS_Full; +  } +};				/* class JAVA */ + +/* ----------------------------------------------------------------------------- + * swig_java()    - Instantiate module + * ----------------------------------------------------------------------------- */ + +static Language *new_swig_java() { +  return new JAVA(); +} +extern "C" Language *swig_java(void) { +  return new_swig_java(); +} + +/* ----------------------------------------------------------------------------- + * Static member variables + * ----------------------------------------------------------------------------- */ + +const char *JAVA::usage = "\ +Java Options (available with -java)\n\ +     -doxygen        - Convert C++ doxygen comments to JavaDoc comments in proxy classes\n\ +     -debug-doxygen-parser     - Display doxygen parser module debugging information\n\ +     -debug-doxygen-translator - Display doxygen translator module debugging information\n\ +     -nopgcpp        - Suppress premature garbage collection prevention parameter\n\ +     -noproxy        - Generate the low-level functional interface instead\n\ +                       of proxy classes\n\ +     -oldvarnames    - Old intermediary method names for variable wrappers\n\ +     -package <name> - Set name of the Java package to <name>\n\ +\n"; diff --git a/contrib/tools/swig/Source/Modules/javascript.cxx b/contrib/tools/swig/Source/Modules/javascript.cxx new file mode 100644 index 00000000000..17effc220fa --- /dev/null +++ b/contrib/tools/swig/Source/Modules/javascript.cxx @@ -0,0 +1,2490 @@ +/* ----------------------------------------------------------------------------- + * This file is part of SWIG, which is licensed as a whole under version 3 + * (or any later version) of the GNU General Public License. Some additional + * terms also apply to certain portions of SWIG. The full details of the SWIG + * license and copyrights can be found in the LICENSE and COPYRIGHT files + * included with the SWIG source code as distributed by the SWIG developers + * and at https://www.swig.org/legal.html. + * + * javascript.cxx + * + * Javascript language module for SWIG. + * ----------------------------------------------------------------------------- */ + +#include "swigmod.h" +#include "cparse.h" + +/** + * Enables extra debugging information in typemaps. + */ +static bool js_template_enable_debug = false; + +#define ERR_MSG_ONLY_ONE_ENGINE_PLEASE "Only one engine can be specified at a time." + +// keywords used for state variables +#define NAME "name" +#define NAME_MANGLED "name_mangled" +#define TYPE "type" +#define TYPE_MANGLED "type_mangled" +#define WRAPPER_NAME "wrapper" +#define IS_IMMUTABLE "is_immutable" +#define IS_STATIC "is_static" +#define IS_ABSTRACT "is_abstract" +#define GETTER "getter" +#define SETTER "setter" +#define PARENT "parent" +#define PARENT_MANGLED "parent_mangled" +#define CTOR "ctor" +#define CTOR_WRAPPERS "ctor_wrappers" +#define CTOR_DISPATCHERS "ctor_dispatchers" +#define DTOR "dtor" +#define ARGCOUNT "wrap:argc" +#define HAS_TEMPLATES "has_templates" +#define FORCE_CPP "force_cpp" +#define RESET true + +// keys for global state variables +#define CREATE_NAMESPACES "create_namespaces" +#define REGISTER_NAMESPACES "register_namespaces" +#define INITIALIZER "initializer" + +// keys for class scoped state variables +#define MEMBER_VARIABLES "member_variables" +#define MEMBER_FUNCTIONS "member_functions" +#define STATIC_FUNCTIONS "static_functions" +#define STATIC_VARIABLES "static_variables" + + +/** + * A convenience class to manage state variables for emitters. + * The implementation delegates to SWIG Hash DOHs and provides + * named sub-hashes for class, variable, and function states. + */ +class JSEmitterState { + +public: +  JSEmitterState(); +  ~JSEmitterState(); +  DOH *globals(); +  DOH *globals(const char *key, DOH *initial = 0); +  DOH *clazz(bool reset = false); +  DOH *clazz(const char *key, DOH *initial = 0); +  DOH *function(bool reset = false); +  DOH *function(const char *key, DOH *initial = 0); +  DOH *variable(bool reset = false); +  DOH *variable(const char *key, DOH *initial = 0); +  static int IsSet(DOH *val); + +private: +  DOH *getState(const char *key, bool reset = false); +  Hash *globalHash; +}; + +/** + * A convenience class that wraps a code snippet used as template + * for code generation. + */ +class Template { + +public: +  Template(const String *code); +  Template(const String *code, const String *templateName); +  Template(const Template & other); +  ~Template(); +  String *str(); +  Template & replace(const String *pattern, const String *repl); +  Template & print(DOH *doh); +  Template & pretty_print(DOH *doh); +  void operator=(const Template & t); +  Template & trim(); + +private: +  String *code; +  String *templateName; +}; + +/** + * JSEmitter represents an abstraction of javascript code generators + * for different javascript engines. + **/ +class JSEmitter { + +protected: + +  typedef JSEmitterState State; + +  enum MarshallingMode { +    Setter, +    Getter, +    Ctor, +    Function +  }; + +public: + +   enum JSEngine { +     JavascriptCore, +     V8, +     NodeJS +   }; + +   JSEmitter(JSEngine engine); + +   virtual ~ JSEmitter(); + +  /** +   * Opens output files and temporary output DOHs. +   */ +  virtual int initialize(Node *n); + +  /** +   * Writes all collected code into the output file(s). +   */ +  virtual int dump(Node *n) = 0; + +  /** +   * Cleans up all open output DOHs. +   */ +  virtual int close() = 0; + +  /** +   * Switches the context for code generation. +   * +   * Classes, global variables and global functions may need to +   * be registered in certain static tables. +   * This method should be used to switch output DOHs correspondingly. +   */ +  virtual int switchNamespace(Node *); + +  /** +   * Invoked at the beginning of the classHandler. +   */ +  virtual int enterClass(Node *); + +  /** +   * Invoked at the end of the classHandler. +   */ +  virtual int exitClass(Node *) { +    return SWIG_OK; +  } + +  /** +   * Invoked at the beginning of the variableHandler. +   */ +  virtual int enterVariable(Node *); + +  /** +   * Invoked at the end of the variableHandler. +   */ +  virtual int exitVariable(Node *) { +    return SWIG_OK; +  } + +  /** +   * Invoked at the beginning of the functionHandler. +   */ +  virtual int enterFunction(Node *); + +  /** +   * Invoked at the end of the functionHandler. +   */ +  virtual int exitFunction(Node *) { +    return SWIG_OK; +  } + +  /** +   * Invoked by functionWrapper callback after call to Language::functionWrapper. +   */ +  virtual int emitWrapperFunction(Node *n); + +  /** +   * Invoked by nativeWrapper callback +   */ +  virtual int emitNativeFunction(Node *n); + +  /** +   * Invoked from constantWrapper after call to Language::constantWrapper. +   **/ +  virtual int emitConstant(Node *n); + +  /** +   * Registers a given code snippet for a given key name. +   * +   * This method is called by the fragmentDirective handler +   * of the JAVASCRIPT language module. +   **/ +  int registerTemplate(const String *name, const String *code); + +  /** +   * Retrieve the code template registered for a given name. +   */ +  Template getTemplate(const String *name); + +  State & getState(); + +protected: + +  /** +   * Generates code for a constructor function. +   */ +  virtual int emitCtor(Node *n); + +  /** +   * Generates code for a destructor function. +   */ +  virtual int emitDtor(Node *n); + +  /** +   * Generates code for a function. +   */ +  virtual int emitFunction(Node *n, bool is_member, bool is_static); + +  virtual int emitFunctionDispatcher(Node *n, bool /*is_member */ ); + +  /** +   * Generates code for a getter function. +   */ +  virtual int emitGetter(Node *n, bool is_member, bool is_static); + +  /** +   * Generates code for a setter function. +   */ +  virtual int emitSetter(Node *n, bool is_member, bool is_static); + +  virtual void marshalInputArgs(Node *n, ParmList *parms, Wrapper *wrapper, MarshallingMode mode, bool is_member, bool is_static) = 0; + +  virtual String *emitInputTypemap(Node *n, Parm *params, Wrapper *wrapper, String *arg); + +  virtual void marshalOutput(Node *n, ParmList *params, Wrapper *wrapper, String *actioncode, const String *cresult = 0, bool emitReturnVariable = true); + +  virtual void emitCleanupCode(Node *n, Wrapper *wrapper, ParmList *params); + +  /** +   * Helper function to retrieve the first parent class node. +   */ +  Node *getBaseClass(Node *n); + +  Parm *skipIgnoredArgs(Parm *p); + +  virtual int createNamespace(String *scope); + +  virtual Hash *createNamespaceEntry(const char *name, const char *parent, const char *parent_mangled); + +  virtual int emitNamespaces() = 0; + + +protected: + +  JSEngine engine; +  Hash *templates; +  State state; + +  // contains context specific data (DOHs) +  // to allow generation of namespace related code +  // which are switched on namespace change +  Hash *namespaces; +  Hash *current_namespace; +  String *defaultResultName; +  File *f_wrappers; +}; + +/* factory methods for concrete JSEmitters: */ + +JSEmitter *swig_javascript_create_JSCEmitter(); +JSEmitter *swig_javascript_create_V8Emitter(); +JSEmitter *swig_javascript_create_NodeJSEmitter(); + +/********************************************************************** + * JAVASCRIPT: SWIG module implementation + **********************************************************************/ + +class JAVASCRIPT:public Language { + +public: + +  JAVASCRIPT():emitter(NULL) { +  } +  ~JAVASCRIPT() { +    delete emitter; +  } + +  virtual int functionHandler(Node *n); +  virtual int globalfunctionHandler(Node *n); +  virtual int variableHandler(Node *n); +  virtual int globalvariableHandler(Node *n); +  virtual int staticmemberfunctionHandler(Node *n); +  virtual int classHandler(Node *n); +  virtual int functionWrapper(Node *n); +  virtual int constantWrapper(Node *n); +  virtual int nativeWrapper(Node *n); +  virtual void main(int argc, char *argv[]); +  virtual int top(Node *n); + +  /** +   *  Registers all %fragments assigned to section "templates". +   **/ +  virtual int fragmentDirective(Node *n); + +public: + +  virtual String *getNSpace() const; + +private: + +  JSEmitter *emitter; +}; + +/* --------------------------------------------------------------------- + * functionWrapper() + * + * Low level code generator for functions + * --------------------------------------------------------------------- */ + +int JAVASCRIPT::functionWrapper(Node *n) { + +  // note: the default implementation only prints a message +  // Language::functionWrapper(n); +  emitter->emitWrapperFunction(n); + +  return SWIG_OK; +} + +/* --------------------------------------------------------------------- + * functionHandler() + * + * Function handler for generating wrappers for functions + * --------------------------------------------------------------------- */ +int JAVASCRIPT::functionHandler(Node *n) { + +  if (GetFlag(n, "isextension") == 1) { +    SetFlag(n, "ismember"); +  } + +  emitter->enterFunction(n); +  Language::functionHandler(n); +  emitter->exitFunction(n); + +  return SWIG_OK; +} + +/* --------------------------------------------------------------------- + * globalfunctionHandler() + * + * Function handler for generating wrappers for functions + * --------------------------------------------------------------------- */ + +int JAVASCRIPT::globalfunctionHandler(Node *n) { +  emitter->switchNamespace(n); +  Language::globalfunctionHandler(n); + +  return SWIG_OK; +} + +/* --------------------------------------------------------------------- + * staticmemberfunctionHandler() + * + * Function handler for generating wrappers for static member functions + * --------------------------------------------------------------------- */ + +int JAVASCRIPT::staticmemberfunctionHandler(Node *n) { +  /* +   *  Note: storage=static is removed by Language::staticmemberfunctionHandler. +   *    So, don't rely on that after here. Instead use the state variable which is +   *    set by JSEmitter::enterFunction(). +   */ +  Language::staticmemberfunctionHandler(n); +  return SWIG_OK; +} + +/* --------------------------------------------------------------------- + * variableHandler() + * + * Function handler for generating wrappers for variables + * --------------------------------------------------------------------- */ + +int JAVASCRIPT::variableHandler(Node *n) { + +  emitter->enterVariable(n); +  Language::variableHandler(n); +  emitter->exitVariable(n); + +  return SWIG_OK; +} + +/* --------------------------------------------------------------------- + * globalvariableHandler() + * + * Function handler for generating wrappers for global variables + * --------------------------------------------------------------------- */ + +int JAVASCRIPT::globalvariableHandler(Node *n) { +  emitter->switchNamespace(n); +  Language::globalvariableHandler(n); + +  return SWIG_OK; +} + +/* --------------------------------------------------------------------- + * constantHandler() + * + * Function handler for generating wrappers for constants + * --------------------------------------------------------------------- */ + +int JAVASCRIPT::constantWrapper(Node *n) { +  emitter->switchNamespace(n); + +  // Note: callbacks trigger this wrapper handler +  // TODO: handle callback declarations +  if (Equal(Getattr(n, "kind"), "function")) { +    return SWIG_OK; +  } +  // TODO: the emitter for constants must be implemented in a cleaner way +  // currently we treat it like a read-only variable +  // however, there is a remaining bug with function pointer constants +  // which could be fixed with a cleaner approach +  emitter->emitConstant(n); + +  return SWIG_OK; +} + +/* --------------------------------------------------------------------- + * nativeWrapper() + * + * Function wrapper for generating placeholders for native functions + * --------------------------------------------------------------------- */ + +int JAVASCRIPT::nativeWrapper(Node *n) { +  emitter->emitNativeFunction(n); + +  return SWIG_OK; +} + +/* --------------------------------------------------------------------- + * classHandler() + * + * Function handler for generating wrappers for class + * --------------------------------------------------------------------- */ + +int JAVASCRIPT::classHandler(Node *n) { +  emitter->switchNamespace(n); + +  emitter->enterClass(n); +  Language::classHandler(n); +  emitter->exitClass(n); + +  return SWIG_OK; +} + +int JAVASCRIPT::fragmentDirective(Node *n) { + +  // catch all fragment directives that have "templates" as location +  // and register them at the emitter. +  String *section = Getattr(n, "section"); + +  if (Equal(section, "templates") && !ImportMode) { +    emitter->registerTemplate(Getattr(n, "value"), Getattr(n, "code")); +  } else { +    return Language::fragmentDirective(n); +  } + +  return SWIG_OK; +} + +String *JAVASCRIPT::getNSpace() const { +  return Language::getNSpace(); +} + +/* --------------------------------------------------------------------- + * top() + * + * Function handler for processing top node of the parse tree + * Wrapper code generation essentially starts from here + * --------------------------------------------------------------------- */ + +int JAVASCRIPT::top(Node *n) { +  emitter->initialize(n); + +  Language::top(n); + +  emitter->dump(n); +  emitter->close(); + +  return SWIG_OK; +} + +static const char *usage = (char *) "\ +Javascript Options (available with -javascript)\n\ +     -jsc                   - creates a JavascriptCore extension \n\ +     -v8                    - creates a v8 extension \n\ +     -node                  - creates a node.js extension \n\ +     -debug-codetemplates   - generates information about the origin of code templates\n"; + + +/* --------------------------------------------------------------------- + * main() + * + * Entry point for the JAVASCRIPT module + * --------------------------------------------------------------------- */ + +void JAVASCRIPT::main(int argc, char *argv[]) { +  // Set javascript subdirectory in SWIG library +  SWIG_library_directory("javascript"); + +  int engine = -1; + +  for (int i = 1; i < argc; i++) { +    if (argv[i]) { +      if (strcmp(argv[i], "-v8") == 0) { +      	if (engine != -1) { +	  Printf(stderr, ERR_MSG_ONLY_ONE_ENGINE_PLEASE); +	  Exit(EXIT_FAILURE); +      	} +	Swig_mark_arg(i); +	engine = JSEmitter::V8; +      } else if (strcmp(argv[i], "-jsc") == 0) { +      	if (engine != -1) { +	  Printf(stderr, ERR_MSG_ONLY_ONE_ENGINE_PLEASE); +	  Exit(EXIT_FAILURE); +      	} +	Swig_mark_arg(i); +	engine = JSEmitter::JavascriptCore; +      } else if (strcmp(argv[i], "-node") == 0) { +      	if (engine != -1) { +	  Printf(stderr, ERR_MSG_ONLY_ONE_ENGINE_PLEASE); +	  Exit(EXIT_FAILURE); +      	} +	Swig_mark_arg(i); +	engine = JSEmitter::NodeJS; +      } else if (strcmp(argv[i], "-debug-codetemplates") == 0) { +	Swig_mark_arg(i); +	js_template_enable_debug = true; +      } else if (strcmp(argv[i], "-help") == 0) { +	fputs(usage, stdout); +	return; +      } +    } +  } + +  switch (engine) { +  case JSEmitter::V8: +    { +      emitter = swig_javascript_create_V8Emitter(); +      Preprocessor_define("SWIG_JAVASCRIPT_V8 1", 0); +      SWIG_library_directory("javascript/v8"); +      // V8 API is C++, so output must be C++ compatible even when wrapping C code +      if (!cparse_cplusplus) { +	Swig_cparse_cplusplusout(1); +      } +      break; +    } +  case JSEmitter::JavascriptCore: +    { +      emitter = swig_javascript_create_JSCEmitter(); +      Preprocessor_define("SWIG_JAVASCRIPT_JSC 1", 0); +      SWIG_library_directory("javascript/jsc"); +      break; +    } +  case JSEmitter::NodeJS: +    { +      emitter = swig_javascript_create_V8Emitter(); +      Preprocessor_define("SWIG_JAVASCRIPT_V8 1", 0); +      Preprocessor_define("BUILDING_NODE_EXTENSION 1", 0); +      SWIG_library_directory("javascript/v8"); +      break; +    } +  default: +    { +      Printf(stderr, "SWIG Javascript: Unknown engine. Please specify one of '-jsc', '-v8' or '-node'.\n"); +      Exit(EXIT_FAILURE); +      break; +    } +  } + +  // Add a symbol to the parser for conditional compilation +  Preprocessor_define("SWIGJAVASCRIPT 1", 0); + +  // Add typemap definitions +  SWIG_typemap_lang("javascript"); + +  // Set configuration file +  SWIG_config_file("javascript.swg"); + +  allow_overloading(); +} + +/* ----------------------------------------------------------------------------- + * swig_javascript()    - Instantiate module + * ----------------------------------------------------------------------------- */ + +static Language *new_swig_javascript() { +  return new JAVASCRIPT(); +} + +extern "C" Language *swig_javascript(void) { +  return new_swig_javascript(); +} + +/********************************************************************** + * Emitter implementations + **********************************************************************/ + +/* ----------------------------------------------------------------------------- + * JSEmitter() + * ----------------------------------------------------------------------------- */ + +JSEmitter::JSEmitter(JSEmitter::JSEngine engine) +:  engine(engine), templates(NewHash()), namespaces(NULL), current_namespace(NULL), defaultResultName(NewString("result")), f_wrappers(NULL) { +} + +/* ----------------------------------------------------------------------------- + * ~JSEmitter() + * ----------------------------------------------------------------------------- */ + +JSEmitter::~JSEmitter() { +  Delete(templates); +} + +/* ----------------------------------------------------------------------------- + * JSEmitter::RegisterTemplate() :  Registers a code template + * + *  Note: this is used only by JAVASCRIPT::fragmentDirective(). + * ----------------------------------------------------------------------------- */ + +int JSEmitter::registerTemplate(const String *name, const String *code) { +  if (!State::IsSet(state.globals(HAS_TEMPLATES))) { +    SetFlag(state.globals(), HAS_TEMPLATES); +  } +  return Setattr(templates, name, code); +} + +/* ----------------------------------------------------------------------------- + * JSEmitter::getTemplate() :  Provides a registered code template + * ----------------------------------------------------------------------------- */ + +Template JSEmitter::getTemplate(const String *name) { +  String *templ = Getattr(templates, name); + +  if (!templ) { +    Printf(stderr, "Could not find template %s\n.", name); +    Exit(EXIT_FAILURE); +  } + +  Template t(templ, name); +  return t; +} + +JSEmitterState & JSEmitter::getState() { +  return state; +} + +int JSEmitter::initialize(Node * /*n */ ) { + +  if (namespaces != NULL) { +    Delete(namespaces); +  } +  namespaces = NewHash(); +  Hash *global_namespace = createNamespaceEntry("exports", 0, 0); + +  Setattr(namespaces, "::", global_namespace); +  current_namespace = global_namespace; + +  f_wrappers = NewString(""); + +  return SWIG_OK; +} + +/* --------------------------------------------------------------------- + * skipIgnoredArgs() + * --------------------------------------------------------------------- */ + +Parm *JSEmitter::skipIgnoredArgs(Parm *p) { +  while (checkAttribute(p, "tmap:in:numinputs", "0")) { +    p = Getattr(p, "tmap:in:next"); +  } +  return p; +} + +/* ----------------------------------------------------------------------------- + * JSEmitter::getBaseClass() :  the node of the base class or NULL + * + * Note: the first base class is provided. Multiple inheritance is not + *       supported. + * ----------------------------------------------------------------------------- */ + +Node *JSEmitter::getBaseClass(Node *n) { +  // retrieve the first base class that is not %ignored +  List *baselist = Getattr(n, "bases"); +  if (baselist) { +    Iterator base = First(baselist); +    while (base.item && GetFlag(base.item, "feature:ignore")) { +      base = Next(base); +    } +    return base.item; +  } +  return NULL; +} + + /* ----------------------------------------------------------------------------- +  * JSEmitter::emitWrapperFunction() :  dispatches emitter functions. +  * +  * This allows having small sized, dedicated emitting functions. +  * All state dependent branching is done here. +  * ----------------------------------------------------------------------------- */ + +int JSEmitter::emitWrapperFunction(Node *n) { +  int ret = SWIG_OK; + +  String *kind = Getattr(n, "kind"); + +  if (kind) { + +    if (Equal(kind, "function") +	// HACK: sneaky.ctest revealed that typedef'd (global) functions must be +	// detected via the 'view' attribute. +	|| (Equal(kind, "variable") && Equal(Getattr(n, "view"), "globalfunctionHandler")) +	) { +      bool is_member = GetFlag(n, "ismember") != 0 || GetFlag(n, "feature:extend") != 0; +      bool is_static = GetFlag(state.function(), IS_STATIC) != 0; +      ret = emitFunction(n, is_member, is_static); +    } else if (Cmp(kind, "variable") == 0) { +      bool is_static = GetFlag(state.variable(), IS_STATIC) != 0; +      // HACK: smartpointeraccessed static variables are not treated as statics +      if (GetFlag(n, "allocate:smartpointeraccess")) { +	is_static = false; +      } + +      bool is_member = GetFlag(n, "ismember") != 0; +      bool is_setter = GetFlag(n, "memberset") != 0 || GetFlag(n, "varset") != 0; +      bool is_getter = GetFlag(n, "memberget") != 0 || GetFlag(n, "varget") != 0; +      if (is_setter) { +	ret = emitSetter(n, is_member, is_static); +      } else if (is_getter) { +	ret = emitGetter(n, is_member, is_static); +      } + +    } else { +      Printf(stderr, "Warning: unsupported wrapper function type\n"); +      ret = SWIG_ERROR; +    } +  } else { +    String *view = Getattr(n, "view"); + +    if (Cmp(view, "constructorHandler") == 0) { +      ret = emitCtor(n); +    } else if (Cmp(view, "destructorHandler") == 0) { +      ret = emitDtor(n); +    } else { +      Printf(stderr, "Warning: unsupported wrapper function type"); +      ret = SWIG_ERROR; +    } +  } + +  return ret; +} + +int JSEmitter::emitNativeFunction(Node *n) { +  String *wrapname = Getattr(n, "wrap:name"); +  enterFunction(n); +  state.function(WRAPPER_NAME, wrapname); +  exitFunction(n); +  return SWIG_OK; +} + +int JSEmitter::enterClass(Node *n) { +  state.clazz(RESET); +  state.clazz(NAME, Getattr(n, "sym:name")); +  state.clazz("nspace", current_namespace); + +  // Creating a mangled name using the current namespace and the symbol name +  String *mangled_name = NewString(""); +  Printf(mangled_name, "%s_%s", Getattr(current_namespace, NAME_MANGLED), Getattr(n, "sym:name")); +  state.clazz(NAME_MANGLED, SwigType_manglestr(mangled_name)); +  Delete(mangled_name); + +  state.clazz(TYPE, NewString(Getattr(n, "classtype"))); + +  String *type = SwigType_manglestr(Getattr(n, "classtypeobj")); +  String *classtype_mangled = NewString(""); +  Printf(classtype_mangled, "p%s", type); +  state.clazz(TYPE_MANGLED, classtype_mangled); +  Delete(type); + +  String *ctor_wrapper = NewString("_wrap_new_veto_"); +  Append(ctor_wrapper, state.clazz(NAME)); +  state.clazz(CTOR, ctor_wrapper); +  state.clazz(CTOR_DISPATCHERS, NewString("")); +  state.clazz(DTOR, NewString("0")); + +  // HACK: assume that a class is abstract +  // this is resolved by emitCtor (which is only called for non abstract classes) +  SetFlag(state.clazz(), IS_ABSTRACT); + +  return SWIG_OK; +} + +int JSEmitter::enterFunction(Node *n) { +  state.function(RESET); +  state.function(NAME, Getattr(n, "sym:name")); +  if (Equal(Getattr(n, "storage"), "static")) { +    SetFlag(state.function(), IS_STATIC); +  } +  return SWIG_OK; +} + +int JSEmitter::enterVariable(Node *n) { +  // reset the state information for variables. +  state.variable(RESET); + +  // Retrieve a pure symbol name. Using 'sym:name' as a basis, as it considers %renamings. +  if (Equal(Getattr(n, "view"), "memberconstantHandler")) { +    // Note: this is kind of hacky/experimental +    // For constants/enums 'sym:name' contains e.g., 'Foo_Hello' instead of 'Hello' +    state.variable(NAME, Getattr(n, "memberconstantHandler:sym:name")); +  } else { +    state.variable(NAME, Swig_scopename_last(Getattr(n, "sym:name"))); +  } + +  if (Equal(Getattr(n, "storage"), "static")) { +    SetFlag(state.variable(), IS_STATIC); +  } + +  if (!Language::instance()->is_assignable(n)) { +    SetFlag(state.variable(), IS_IMMUTABLE); +  } +  // FIXME: test "arrays_global" does not compile with that as it is not allowed to assign to char[] +  if (Equal(Getattr(n, "type"), "a().char")) { +    SetFlag(state.variable(), IS_IMMUTABLE); +  } + +  return SWIG_OK; +} + +int JSEmitter::emitCtor(Node *n) { + +  Wrapper *wrapper = NewWrapper(); + +  bool is_overloaded = GetFlag(n, "sym:overloaded") != 0; + +  Template t_ctor(getTemplate("js_ctor")); + +  String *wrap_name = Swig_name_wrapper(Getattr(n, "sym:name")); +  if (is_overloaded) { +    t_ctor = getTemplate("js_overloaded_ctor"); +    Append(wrap_name, Getattr(n, "sym:overname")); +  } +  Setattr(n, "wrap:name", wrap_name); +  // note: we can remove the is_abstract flag now, as this +  //       is called for non-abstract classes only. +  Setattr(state.clazz(), IS_ABSTRACT, 0); + +  ParmList *params = Getattr(n, "parms"); +  emit_parameter_variables(params, wrapper); +  emit_attach_parmmaps(params, wrapper); +  // HACK: in test-case `ignore_parameter` emit_attach_parmmaps generated an extra line of applied typemaps. +  // Deleting wrapper->code here, to reset, and as it seemed to have no side effect elsewhere +  Delete(wrapper->code); +  wrapper->code = NewString(""); + +  Printf(wrapper->locals, "%sresult;", SwigType_str(Getattr(n, "type"), 0)); + +  marshalInputArgs(n, params, wrapper, Ctor, true, false); +  String *action = emit_action(n); +  Printv(wrapper->code, action, "\n", 0); + +  emitCleanupCode(n, wrapper, params); + +  t_ctor.replace("$jswrapper", wrap_name) +      .replace("$jsmangledtype", state.clazz(TYPE_MANGLED)) +      .replace("$jslocals", wrapper->locals) +      .replace("$jscode", wrapper->code) +      .replace("$jsargcount", Getattr(n, ARGCOUNT)) +      .pretty_print(f_wrappers); + +  Template t_ctor_case(getTemplate("js_ctor_dispatch_case")); +  t_ctor_case.replace("$jswrapper", wrap_name) +      .replace("$jsargcount", Getattr(n, ARGCOUNT)); +  Append(state.clazz(CTOR_DISPATCHERS), t_ctor_case.str()); + +  DelWrapper(wrapper); + +  // create a dispatching ctor +  if (is_overloaded) { +    if (!Getattr(n, "sym:nextSibling")) { +      String *wrap_name = Swig_name_wrapper(Getattr(n, "sym:name")); +      Template t_mainctor(getTemplate("js_ctor_dispatcher")); +      t_mainctor.replace("$jswrapper", wrap_name) +	  .replace("$jsmangledname", state.clazz(NAME_MANGLED)) +	  .replace("$jsdispatchcases", state.clazz(CTOR_DISPATCHERS)) +	  .pretty_print(f_wrappers); +      state.clazz(CTOR, wrap_name); +    } +  } else { +    state.clazz(CTOR, wrap_name); +  } + +  return SWIG_OK; +} + +int JSEmitter::emitDtor(Node *n) { + +  String *wrap_name = Swig_name_wrapper(Getattr(n, "sym:name")); + +  SwigType *type = state.clazz(TYPE); +  String *p_classtype = SwigType_add_pointer(state.clazz(TYPE)); +  String *ctype = SwigType_lstr(p_classtype, ""); +  String *jsfree = NewString(""); + +  // (Taken from JSCore implementation.) +  /* The if (Extend) block was taken from the Ruby implementation. +   * The problem is that in the case of an %extend to create a destructor for a struct to coordinate automatic memory cleanup with the Javascript collector, +   * the SWIG function was not being generated. More specifically: +   struct MyData { +   %extend { +   ~MyData() { +   FreeData($self); +   } +   } +   }; +   %newobject CreateData; +   struct MyData* CreateData(void); +   %delobject FreeData; +   void FreeData(struct MyData* the_data); + +   where the use case is something like: +   var my_data = example.CreateData(); +   my_data = null; + +   This function was not being generated: +   SWIGINTERN void delete_MyData(struct MyData *self){ +   FreeData(self); +   } + +   I don't understand fully why it wasn't being generated. It just seems to happen in the Lua generator. +   There is a comment about staticmemberfunctionHandler having an inconsistency and I tracked down dome of the SWIGINTERN void delete_* +   code to that function in the Language base class. +   The Ruby implementation seems to have an explicit check for if(Extend) and explicitly generates the code, so that's what I'm doing here. +   The Ruby implementation does other stuff which I omit. +   */ +  if (Extend) { +    String *wrap = Getattr(n, "wrap:code"); +    if (wrap) { +      Printv(f_wrappers, wrap, NIL); +    } +  } +  // HACK: this is only for the v8 emitter. maybe set an attribute wrap:action of node +  // TODO: generate dtors more similar to other wrappers +  // EW: I think this is wrong. delete should only be used when new was used to create. If malloc was used, free needs to be used. +  if (SwigType_isarray(type)) { +    Printf(jsfree, "delete [] (%s)", ctype); +  } else { +    Printf(jsfree, "delete (%s)", ctype); +  } + +  String *destructor_action = Getattr(n, "wrap:action"); +  // Adapted from the JSCore implementation. +  /* The next challenge is to generate the correct finalize function for JavaScriptCore to call. +     Originally, it would use this fragment from javascriptcode.swg +     %fragment ("JS_destructordefn", "templates") +     %{ +     void _wrap_${classname_mangled}_finalize(JSObjectRef thisObject) +     { +     SWIG_PRV_DATA* t = (SWIG_PRV_DATA*)JSObjectGetPrivate(thisObject); +     if(t && t->swigCMemOwn) free ((${type}*)t->swigCObject); +     free(t); +     } +     %} + +     But for the above example case of %extend to define a destructor on a struct, we need to override the system to not call +     free ((${type}*)t->swigCObject); +     and substitute it with what the user has provided. +     To solve this, I created a variation fragment called JS_destructoroverridedefn: +     SWIG_PRV_DATA* t = (SWIG_PRV_DATA*)JSObjectGetPrivate(thisObject); +     if(t && t->swigCMemOwn) { +     ${type}* arg1 = (${type}*)t->swigCObject; +     ${destructor_action} +     } +     free(t); + +     Based on what I saw in the Lua and Ruby modules, I use Getattr(n, "wrap:action") +     to decide if the user has a preferred destructor action. +     Based on that, I decide which fragment to use. +     And in the case of the custom action, I substitute that action in. +     I noticed that destructor_action has the form +     delete_MyData(arg1); +     The explicit arg1 is a little funny, so I structured the fragment to create a temporary variable called arg1 to make the generation easier. +     This might suggest this solution misunderstands a more complex case. + +     Also, there is a problem where destructor_action is always true for me, even when not requesting %extend as above. +     So this code doesn't actually quite work as I expect. The end result is that the code still works because +     destructor_action calls free like the original template. The one caveat is the string in destructor_action casts to char* which is weird. +     I think there is a deeper underlying SWIG issue because I don't think it should be char*. However, it doesn't really matter for free. + +     Maybe the fix for the destructor_action always true problem is that this is supposed to be embedded in the if(Extend) block above. +     But I don't fully understand the conditions of any of these things, and since it works for the moment, I don't want to break more stuff. +   */ +  if (destructor_action) { +    Template t_dtor = getTemplate("js_dtoroverride"); +    state.clazz(DTOR, wrap_name); +    t_dtor.replace("${classname_mangled}", state.clazz(NAME_MANGLED)) +	.replace("$jswrapper", wrap_name) +	.replace("$jsfree", jsfree) +	.replace("$jstype", ctype); + +    t_dtor.replace("${destructor_action}", destructor_action); +    Wrapper_pretty_print(t_dtor.str(), f_wrappers); +  } else { +    Template t_dtor = getTemplate("js_dtor"); +    state.clazz(DTOR, wrap_name); +    t_dtor.replace("$jsmangledname", state.clazz(NAME_MANGLED)) +	.replace("$jswrapper", wrap_name) +	.replace("$jsfree", jsfree) +	.replace("$jstype", ctype) +	.pretty_print(f_wrappers); +  } + +  Delete(p_classtype); +  Delete(ctype); +  Delete(jsfree); + +  return SWIG_OK; +} + +int JSEmitter::emitGetter(Node *n, bool is_member, bool is_static) { +  Wrapper *wrapper = NewWrapper(); +  Template t_getter(getTemplate("js_getter")); + +  // prepare wrapper name +  String *wrap_name = Swig_name_wrapper(Getattr(n, "sym:name")); +  Setattr(n, "wrap:name", wrap_name); +  state.variable(GETTER, wrap_name); + +  // prepare local variables +  ParmList *params = Getattr(n, "parms"); +  emit_parameter_variables(params, wrapper); +  emit_attach_parmmaps(params, wrapper); + +  // prepare code part +  String *action = emit_action(n); +  marshalInputArgs(n, params, wrapper, Getter, is_member, is_static); +  marshalOutput(n, params, wrapper, action); + +  emitCleanupCode(n, wrapper, params); + +  t_getter.replace("$jswrapper", wrap_name) +      .replace("$jslocals", wrapper->locals) +      .replace("$jscode", wrapper->code) +      .pretty_print(f_wrappers); + +  DelWrapper(wrapper); + +  return SWIG_OK; +} + +int JSEmitter::emitSetter(Node *n, bool is_member, bool is_static) { + +  // skip variables that are immutable +  if (State::IsSet(state.variable(IS_IMMUTABLE))) { +    return SWIG_OK; +  } + +  Wrapper *wrapper = NewWrapper(); + +  Template t_setter(getTemplate("js_setter")); + +  // prepare wrapper name +  String *wrap_name = Swig_name_wrapper(Getattr(n, "sym:name")); +  Setattr(n, "wrap:name", wrap_name); +  state.variable(SETTER, wrap_name); + +  // prepare local variables +  ParmList *params = Getattr(n, "parms"); +  emit_parameter_variables(params, wrapper); +  emit_attach_parmmaps(params, wrapper); + +  // prepare code part +  String *action = emit_action(n); +  marshalInputArgs(n, params, wrapper, Setter, is_member, is_static); +  Append(wrapper->code, action); + +  emitCleanupCode(n, wrapper, params); + +  t_setter.replace("$jswrapper", wrap_name) +      .replace("$jslocals", wrapper->locals) +      .replace("$jscode", wrapper->code) +      .pretty_print(f_wrappers); + +  DelWrapper(wrapper); + +  return SWIG_OK; +} + +/* ----------------------------------------------------------------------------- + * JSEmitter::emitConstant() :  triggers code generation for constants + * ----------------------------------------------------------------------------- */ + +int JSEmitter::emitConstant(Node *n) { +  // HACK: somehow it happened under Mac OS X that before everything started +  // a lot of SWIG internal constants were emitted +  // This didn't happen on other platforms yet... +  // we ignore those premature definitions +  if (!State::IsSet(state.globals(HAS_TEMPLATES))) { +    return SWIG_ERROR; +  } + +  Wrapper *wrapper = NewWrapper(); +  SwigType *type = Getattr(n, "type"); +  String *name = Getattr(n, "name"); +  String *iname = Getattr(n, "sym:name"); +  String *wname = Swig_name_wrapper(name); +  String *rawval = Getattr(n, "rawval"); +  String *value = rawval ? rawval : Getattr(n, "value"); + +  // HACK: forcing usage of cppvalue for v8 (which turned out to fix typedef_struct.i, et. al) +  if (State::IsSet(state.globals(FORCE_CPP)) && Getattr(n, "cppvalue") != NULL) { +    value = Getattr(n, "cppvalue"); +  } + +  Template t_getter(getTemplate("js_getter")); + +  // call the variable methods as a constants are +  // registered in same way +  enterVariable(n); +  state.variable(GETTER, wname); +  // TODO: why do we need this? +  Setattr(n, "wrap:name", wname); + +  // special treatment of member pointers +  if (SwigType_type(type) == T_MPOINTER) { +    // TODO: this could go into a code-template +    String *mpointer_wname = NewString(""); +    Printf(mpointer_wname, "_wrapConstant_%s", iname); +    Setattr(n, "memberpointer:constant:wrap:name", mpointer_wname); +    String *str = SwigType_str(type, mpointer_wname); +    Printf(f_wrappers, "static %s = %s;\n", str, value); +    Delete(str); +    value = mpointer_wname; +  } + +  marshalOutput(n, 0, wrapper, NewString(""), value, false); + +  t_getter.replace("$jswrapper", wname) +      .replace("$jslocals", wrapper->locals) +      .replace("$jscode", wrapper->code) +      .pretty_print(f_wrappers); + +  exitVariable(n); + +  DelWrapper(wrapper); + +  return SWIG_OK; +} + +int JSEmitter::emitFunction(Node *n, bool is_member, bool is_static) { +  Wrapper *wrapper = NewWrapper(); +  Template t_function(getTemplate("js_function")); + +  bool is_overloaded = GetFlag(n, "sym:overloaded") != 0; + +  // prepare the function wrapper name +  String *iname = Getattr(n, "sym:name"); +  String *wrap_name = Swig_name_wrapper(iname); +  if (is_overloaded) { +    t_function = getTemplate("js_overloaded_function"); +    Append(wrap_name, Getattr(n, "sym:overname")); +  } +  Setattr(n, "wrap:name", wrap_name); +  state.function(WRAPPER_NAME, wrap_name); + +  // prepare local variables +  ParmList *params = Getattr(n, "parms"); +  emit_parameter_variables(params, wrapper); +  emit_attach_parmmaps(params, wrapper); + +  // HACK: in test-case `ignore_parameter` emit_attach_parmmaps generates an extra line of applied typemap. +  // Deleting wrapper->code here fixes the problem, and seems to have no side effect elsewhere +  Delete(wrapper->code); +  wrapper->code = NewString(""); + +  marshalInputArgs(n, params, wrapper, Function, is_member, is_static); +  String *action = emit_action(n); +  marshalOutput(n, params, wrapper, action); +  emitCleanupCode(n, wrapper, params); +  Replaceall(wrapper->code, "$symname", iname); + +  t_function.replace("$jswrapper", wrap_name) +      .replace("$jslocals", wrapper->locals) +      .replace("$jscode", wrapper->code) +      .replace("$jsargcount", Getattr(n, ARGCOUNT)) +      .pretty_print(f_wrappers); + + +  DelWrapper(wrapper); + +  return SWIG_OK; +} + +int JSEmitter::emitFunctionDispatcher(Node *n, bool /*is_member */ ) { +  Wrapper *wrapper = NewWrapper(); + +  // Generate call list, go to first node +  Node *sibl = n; + +  while (Getattr(sibl, "sym:previousSibling")) +    sibl = Getattr(sibl, "sym:previousSibling");	// go all the way up + +  do { +    String *siblname = Getattr(sibl, "wrap:name"); + +    if (siblname) { +      // handle function overloading +      Template t_dispatch_case = getTemplate("js_function_dispatch_case"); +      t_dispatch_case.replace("$jswrapper", siblname) +	  .replace("$jsargcount", Getattr(sibl, ARGCOUNT)); + +      Append(wrapper->code, t_dispatch_case.str()); +    } + +  } while ((sibl = Getattr(sibl, "sym:nextSibling"))); + +  Template t_function(getTemplate("js_function_dispatcher")); + +  // Note: this dispatcher function gets called after the last overloaded function has been created. +  // At this time, n.wrap:name contains the name of the last wrapper function. +  // To get a valid function name for the dispatcher function we take the last wrapper name and +  // subtract the extension "sym:overname", +  String *wrap_name = NewString(Getattr(n, "wrap:name")); +  String *overname = Getattr(n, "sym:overname"); + +  Node *methodclass = Swig_methodclass(n); +  String *class_name = Getattr(methodclass, "sym:name"); + +  int l1 = Len(wrap_name); +  int l2 = Len(overname); +  Delslice(wrap_name, l1 - l2, l1); + +  String *new_string = NewStringf("%s_%s", class_name, wrap_name); +  String *final_wrap_name = Swig_name_wrapper(new_string); +      +  Setattr(n, "wrap:name", final_wrap_name); +  state.function(WRAPPER_NAME, final_wrap_name); + + + +  t_function.replace("$jslocals", wrapper->locals) +      .replace("$jscode", wrapper->code); + +  // call this here, to replace all variables +  t_function.replace("$jswrapper", final_wrap_name) +      .replace("$jsname", state.function(NAME)) +      .pretty_print(f_wrappers); + +  // Delete the state variable +  DelWrapper(wrapper); + +  return SWIG_OK; +} + +String *JSEmitter::emitInputTypemap(Node *n, Parm *p, Wrapper *wrapper, String *arg) { +  // Get input typemap for current param +  String *tm = Getattr(p, "tmap:in"); +  SwigType *type = Getattr(p, "type"); + +  if (tm != NULL) { +    Replaceall(tm, "$input", arg); +    Setattr(p, "emit:input", arg); +    // do replacements for built-in variables +    if (Getattr(p, "wrap:disown") || (Getattr(p, "tmap:in:disown"))) { +      Replaceall(tm, "$disown", "SWIG_POINTER_DISOWN"); +    } else { +      Replaceall(tm, "$disown", "0"); +    } +    Replaceall(tm, "$symname", Getattr(n, "sym:name")); +    Printf(wrapper->code, "%s\n", tm); +  } else { +    Swig_warning(WARN_TYPEMAP_IN_UNDEF, input_file, line_number, "Unable to use type %s as a function argument.\n", SwigType_str(type, 0)); +  } + +  return tm; +} + +void JSEmitter::marshalOutput(Node *n, ParmList *params, Wrapper *wrapper, String *actioncode, const String *cresult, bool emitReturnVariable) { +  SwigType *type = Getattr(n, "type"); +  String *tm; +  Parm *p; + +  // adds a declaration for the result variable +  if (emitReturnVariable) +    emit_return_variable(n, type, wrapper); +  // if not given, use default result identifier ('result') for output typemap +  if (cresult == 0) +    cresult = defaultResultName; + +  tm = Swig_typemap_lookup_out("out", n, cresult, wrapper, actioncode); +  bool should_own = GetFlag(n, "feature:new") != 0; + +  if (tm) { +    Replaceall(tm, "$objecttype", Swig_scopename_last(SwigType_str(SwigType_strip_qualifiers(type), 0))); + +    if (should_own) { +      Replaceall(tm, "$owner", "SWIG_POINTER_OWN"); +    } else { +      Replaceall(tm, "$owner", "0"); +    } +    Append(wrapper->code, tm); + +    if (Len(tm) > 0) { +      Printf(wrapper->code, "\n"); +    } +  } else { +    Swig_warning(WARN_TYPEMAP_OUT_UNDEF, input_file, line_number, "Unable to use return type %s in function %s.\n", SwigType_str(type, 0), Getattr(n, "name")); +  } + +  if (params) { +    for (p = params; p;) { +      if ((tm = Getattr(p, "tmap:argout"))) { +	Replaceall(tm, "$input", Getattr(p, "emit:input")); +	Printv(wrapper->code, tm, "\n", NIL); +	p = Getattr(p, "tmap:argout:next"); +      } else { +	p = nextSibling(p); +      } +    } +  } + +  Replaceall(wrapper->code, "$result", "jsresult"); +} + +void JSEmitter::emitCleanupCode(Node *n, Wrapper *wrapper, ParmList *params) { +  Parm *p; +  String *tm; + +  for (p = params; p;) { +    if ((tm = Getattr(p, "tmap:freearg"))) { +      //addThrows(n, "tmap:freearg", p); +      Replaceall(tm, "$input", Getattr(p, "emit:input")); +      Printv(wrapper->code, tm, "\n", NIL); +      p = Getattr(p, "tmap:freearg:next"); +    } else { +      p = nextSibling(p); +    } +  } + +  if (GetFlag(n, "feature:new")) { +    tm = Swig_typemap_lookup("newfree", n, Swig_cresult_name(), 0); +    if (tm != NIL) { +      //addThrows(throws_hash, "newfree", n); +      Printv(wrapper->code, tm, "\n", NIL); +    } +  } + +  /* See if there is any return cleanup code */ +  if ((tm = Swig_typemap_lookup("ret", n, Swig_cresult_name(), 0))) { +    Printf(wrapper->code, "%s\n", tm); +    Delete(tm); +  } +} + +int JSEmitter::switchNamespace(Node *n) { +  // HACK: somehow this gets called for member functions. +  // We can safely ignore them, as members are not associated to a namespace (only their class) +  if (GetFlag(n, "ismember")) { +    return SWIG_OK; +  } + +  // if nspace is deactivated, everything goes into the global scope +  if (!GetFlag(n, "feature:nspace")) { +    current_namespace = Getattr(namespaces, "::"); +    return SWIG_OK; +  } + +// EXPERIMENTAL: we want to use Language::getNSpace() here +// However, it is not working yet. +// For namespace functions Language::getNSpace() does not give a valid result +#if 0 +  JAVASCRIPT *lang = static_cast<JAVASCRIPT*>(Language::instance()); +  String *_nspace = lang->getNSpace(); +  if (!Equal(nspace, _nspace)) { +    Printf(stdout, "##### Custom vs Language::getNSpace(): %s | %s\n", nspace, _nspace); +  } +#endif + +  String *nspace = Getattr(n, "sym:nspace"); + +  if (nspace == NULL) { +    // It seems that only classes have 'sym:nspace' set. +    // We try to get the namespace from the qualified name (i.e., everything before the last '::') +    nspace = Swig_scopename_prefix(Getattr(n, "name")); +  } + +  // If there is not even a scopename prefix then it must be global scope +  if (nspace == NULL) { +    current_namespace = Getattr(namespaces, "::"); +    return SWIG_OK; +  } + +  String *scope = NewString(nspace); +  // replace "." with "::" that we can use Swig_scopename_last +  Replaceall(scope, ".", "::"); + +  // if the scope is not yet registered +  // create (parent) namespaces recursively +  if (!Getattr(namespaces, scope)) { +    createNamespace(scope); +  } +  current_namespace = Getattr(namespaces, scope); + +  return SWIG_OK; +} + +int JSEmitter::createNamespace(String *scope) { + +  String *parent_scope = Swig_scopename_prefix(scope); +  Hash *parent_namespace; +  if (parent_scope == 0) { +    parent_namespace = Getattr(namespaces, "::"); +  } else if (!Getattr(namespaces, parent_scope)) { +    createNamespace(parent_scope); +    parent_namespace = Getattr(namespaces, parent_scope); +  } else { +    parent_namespace = Getattr(namespaces, parent_scope); +  } +  assert(parent_namespace != 0); + +  Hash *new_namespace = createNamespaceEntry(Char(scope), Char(Getattr(parent_namespace, "name")), Char(Getattr(parent_namespace, "name_mangled"))); +  Setattr(namespaces, scope, new_namespace); + +  Delete(parent_scope); +  return SWIG_OK; +} + +Hash *JSEmitter::createNamespaceEntry(const char *_name, const char *parent, const char *parent_mangled) { +  Hash *entry = NewHash(); +  String *name = NewString(_name); +  Setattr(entry, NAME, Swig_scopename_last(name)); +  Setattr(entry, NAME_MANGLED, Swig_name_mangle(name)); +  Setattr(entry, PARENT, NewString(parent)); +  Setattr(entry, PARENT_MANGLED, NewString(parent_mangled)); + +  Delete(name); +  return entry; +} + +/********************************************************************** + * JavascriptCore: JSEmitter implementation for JavascriptCore engine + **********************************************************************/ + +class JSCEmitter:public JSEmitter { + +public: +  JSCEmitter(); +  virtual ~ JSCEmitter(); +  virtual int initialize(Node *n); +  virtual int dump(Node *n); +  virtual int close(); + +protected: +  virtual int enterVariable(Node *n); +  virtual int exitVariable(Node *n); +  virtual int enterFunction(Node *n); +  virtual int exitFunction(Node *n); +  virtual int enterClass(Node *n); +  virtual int exitClass(Node *n); +  virtual void marshalInputArgs(Node *n, ParmList *parms, Wrapper *wrapper, MarshallingMode mode, bool is_member, bool is_static); +  virtual Hash *createNamespaceEntry(const char *name, const char *parent, const char *parent_mangled); +  virtual int emitNamespaces(); + +private: + +  String *NULL_STR; +  String *VETO_SET; + +  // output file and major code parts +  File *f_wrap_cpp; +  File *f_runtime; +  File *f_header; +  File *f_init; + +}; + +JSCEmitter::JSCEmitter() +:  JSEmitter(JSEmitter::JavascriptCore), NULL_STR(NewString("NULL")), VETO_SET(NewString("JS_veto_set_variable")), f_wrap_cpp(NULL), f_runtime(NULL), f_header(NULL), f_init(NULL) { +} + +JSCEmitter::~JSCEmitter() { +  Delete(NULL_STR); +  Delete(VETO_SET); +} + + +/* --------------------------------------------------------------------- + * marshalInputArgs() + * + * Process all of the arguments passed into the argv array + * and convert them into C/C++ function arguments using the + * supplied typemaps. + * --------------------------------------------------------------------- */ + +void JSCEmitter::marshalInputArgs(Node *n, ParmList *parms, Wrapper *wrapper, MarshallingMode mode, bool is_member, bool is_static) { +  Parm *p; +  String *tm; + +  // determine an offset index, as members have an extra 'this' argument +  // except: static members and ctors. +  int startIdx = 0; +  if (is_member && !is_static && mode != Ctor) { +    startIdx = 1; +  } +  // store number of arguments for argument checks +  int num_args = emit_num_arguments(parms) - startIdx; +  String *argcount = NewString(""); +  Printf(argcount, "%d", num_args); +  Setattr(n, ARGCOUNT, argcount); + +  // process arguments +  int i = 0; +  for (p = parms; p; i++) { +    String *arg = NewString(""); +    String *type = Getattr(p, "type"); + +    // ignore varargs +    if (SwigType_isvarargs(type)) +      break; + +    switch (mode) { +    case Getter: +    case Function: +      if (is_member && !is_static && i == 0) { +	Printv(arg, "thisObject", 0); +      } else { +	Printf(arg, "argv[%d]", i - startIdx); +      } +      break; +    case Setter: +      if (is_member && !is_static && i == 0) { +	Printv(arg, "thisObject", 0); +      } else { +	Printv(arg, "value", 0); +      } +      break; +    case Ctor: +      Printf(arg, "argv[%d]", i); +      break; +    default: +      Printf(stderr, "Illegal MarshallingMode."); +      Exit(EXIT_FAILURE); +    } +    tm = emitInputTypemap(n, p, wrapper, arg); +    Delete(arg); +    if (tm) { +      p = Getattr(p, "tmap:in:next"); +    } else { +      p = nextSibling(p); +    } +  } +} + +int JSCEmitter::initialize(Node *n) { + +  JSEmitter::initialize(n); + +  /* Get the output file name */ +  String *outfile = Getattr(n, "outfile"); + +  /* Initialize I/O */ +  f_wrap_cpp = NewFile(outfile, "w", SWIG_output_files()); +  if (!f_wrap_cpp) { +    FileErrorDisplay(outfile); +    Exit(EXIT_FAILURE); +  } + +  /* Initialization of members */ +  f_runtime = NewString(""); +  f_init = NewString(""); +  f_header = NewString(""); + +  state.globals(CREATE_NAMESPACES, NewString("")); +  state.globals(REGISTER_NAMESPACES, NewString("")); +  state.globals(INITIALIZER, NewString("")); + +  /* Register file targets with the SWIG file handler */ +  Swig_register_filebyname("begin", f_wrap_cpp); +  Swig_register_filebyname("header", f_header); +  Swig_register_filebyname("wrapper", f_wrappers); +  Swig_register_filebyname("runtime", f_runtime); +  Swig_register_filebyname("init", f_init); + +  Swig_banner(f_wrap_cpp); + +  Swig_obligatory_macros(f_runtime, "JAVASCRIPT"); + +  return SWIG_OK; +} + +int JSCEmitter::dump(Node *n) { +  /* Get the module name */ +  String *module = Getattr(n, "name"); + +  Template initializer_define(getTemplate("js_initializer_define")); +  initializer_define.replace("$jsname", module).pretty_print(f_header); + +  SwigType_emit_type_table(f_runtime, f_wrappers); + +  Printv(f_wrap_cpp, f_runtime, "\n", 0); +  Printv(f_wrap_cpp, f_header, "\n", 0); +  Printv(f_wrap_cpp, f_wrappers, "\n", 0); + +  emitNamespaces(); + +  // compose the initializer function using a template +  Template initializer(getTemplate("js_initializer")); +  initializer.replace("$jsname", module) +      .replace("$jsregisterclasses", state.globals(INITIALIZER)) +      .replace("$jscreatenamespaces", state.globals(CREATE_NAMESPACES)) +      .replace("$jsregisternamespaces", state.globals(REGISTER_NAMESPACES)) +      .pretty_print(f_init); + +  Printv(f_wrap_cpp, f_init, 0); + +  return SWIG_OK; +} + +int JSCEmitter::close() { +  Delete(f_runtime); +  Delete(f_header); +  Delete(f_wrappers); +  Delete(f_init); +  Delete(namespaces); +  Delete(f_wrap_cpp); +  return SWIG_OK; +} + +int JSCEmitter::enterFunction(Node *n) { + +  JSEmitter::enterFunction(n); + +  return SWIG_OK; +} + +int JSCEmitter::exitFunction(Node *n) { +  Template t_function = getTemplate("jsc_function_declaration"); + +  bool is_member = GetFlag(n, "ismember") != 0 || GetFlag(n, "feature:extend") != 0; +  bool is_overloaded = GetFlag(n, "sym:overloaded") != 0; + +  // handle overloaded functions +  if (is_overloaded) { +    if (!Getattr(n, "sym:nextSibling")) { +      //state.function(WRAPPER_NAME, Swig_name_wrapper(Getattr(n, "name"))); +      // create dispatcher +      emitFunctionDispatcher(n, is_member); +    } else { +      //don't register wrappers of overloaded functions in function tables +      return SWIG_OK; +    } +  } + +  t_function.replace("$jsname", state.function(NAME)) +      .replace("$jswrapper", state.function(WRAPPER_NAME)); + +  if (is_member) { +    if (GetFlag(state.function(), IS_STATIC)) { +      t_function.pretty_print(state.clazz(STATIC_FUNCTIONS)); +    } else { +      t_function.pretty_print(state.clazz(MEMBER_FUNCTIONS)); +    } +  } else { +    t_function.pretty_print(Getattr(current_namespace, "functions")); +  } + +  return SWIG_OK; +} + +int JSCEmitter::enterVariable(Node *n) { +  JSEmitter::enterVariable(n); +  state.variable(GETTER, NULL_STR); +  state.variable(SETTER, VETO_SET); +  return SWIG_OK; +} + +int JSCEmitter::exitVariable(Node *n) { +  Template t_variable(getTemplate("jsc_variable_declaration")); +  t_variable.replace("$jsname", state.variable(NAME)) +      .replace("$jsgetter", state.variable(GETTER)) +      .replace("$jssetter", state.variable(SETTER)); + +  if (GetFlag(n, "ismember")) { +    if (GetFlag(state.variable(), IS_STATIC) +	|| Equal(Getattr(n, "nodeType"), "enumitem")) { +      t_variable.pretty_print(state.clazz(STATIC_VARIABLES)); +    } else { +      t_variable.pretty_print(state.clazz(MEMBER_VARIABLES)); +    } +  } else { +    t_variable.pretty_print(Getattr(current_namespace, "values")); +  } + +  return SWIG_OK; +} + +int JSCEmitter::enterClass(Node *n) { +  JSEmitter::enterClass(n); +  state.clazz(MEMBER_VARIABLES, NewString("")); +  state.clazz(MEMBER_FUNCTIONS, NewString("")); +  state.clazz(STATIC_VARIABLES, NewString("")); +  state.clazz(STATIC_FUNCTIONS, NewString("")); + +  Template t_class_decl = getTemplate("jsc_class_declaration"); +  t_class_decl.replace("$jsmangledname", state.clazz(NAME_MANGLED)) +      .pretty_print(f_wrappers); + +  return SWIG_OK; +} + +int JSCEmitter::exitClass(Node *n) { +  Template t_class_tables(getTemplate("jsc_class_tables")); +  t_class_tables.replace("$jsmangledname", state.clazz(NAME_MANGLED)) +      .replace("$jsclassvariables", state.clazz(MEMBER_VARIABLES)) +      .replace("$jsclassfunctions", state.clazz(MEMBER_FUNCTIONS)) +      .replace("$jsstaticclassfunctions", state.clazz(STATIC_FUNCTIONS)) +      .replace("$jsstaticclassvariables", state.clazz(STATIC_VARIABLES)) +      .pretty_print(f_wrappers); + +  /* adds the ctor wrappers at this position */ +  // Note: this is necessary to avoid extra forward declarations. +  //Append(f_wrappers, state.clazz(CTOR_WRAPPERS)); + +  // for abstract classes add a vetoing ctor +  if (GetFlag(state.clazz(), IS_ABSTRACT)) { +    Template t_veto_ctor(getTemplate("js_veto_ctor")); +    t_veto_ctor.replace("$jswrapper", state.clazz(CTOR)) +	.replace("$jsname", state.clazz(NAME)) +	.pretty_print(f_wrappers); +  } + +  /* adds a class template statement to initializer function */ +  Template t_classtemplate(getTemplate("jsc_class_definition")); + +  /* prepare registration of base class */ +  String *jsclass_inheritance = NewString(""); +  Node *base_class = getBaseClass(n); +  if (base_class != NULL) { +    Template t_inherit(getTemplate("jsc_class_inherit")); +    t_inherit.replace("$jsmangledname", state.clazz(NAME_MANGLED)) +	.replace("$jsbaseclassmangled", SwigType_manglestr(Getattr(base_class, "name"))) +	.pretty_print(jsclass_inheritance); +  } else { +    Template t_inherit(getTemplate("jsc_class_noinherit")); +    t_inherit.replace("$jsmangledname", state.clazz(NAME_MANGLED)) +	.pretty_print(jsclass_inheritance); +  } + +  t_classtemplate.replace("$jsmangledname", state.clazz(NAME_MANGLED)) +      .replace("$jsmangledtype", state.clazz(TYPE_MANGLED)) +      .replace("$jsclass_inheritance", jsclass_inheritance) +      .replace("$jsctor", state.clazz(CTOR)) +      .replace("$jsdtor", state.clazz(DTOR)) +      .pretty_print(state.globals(INITIALIZER)); +  Delete(jsclass_inheritance); + +  /* Note: this makes sure that there is a swig_type added for this class */ +  SwigType_remember_clientdata(state.clazz(TYPE_MANGLED), NewString("0")); + +  /* adds a class registration statement to initializer function */ +  Template t_registerclass(getTemplate("jsc_class_registration")); +  t_registerclass.replace("$jsname", state.clazz(NAME)) +      .replace("$jsmangledname", state.clazz(NAME_MANGLED)) +      .replace("$jsnspace", Getattr(state.clazz("nspace"), NAME_MANGLED)) +      .pretty_print(state.globals(INITIALIZER)); + +  return SWIG_OK; +} + +Hash *JSCEmitter::createNamespaceEntry(const char *name, const char *parent, const char *parent_mangled) { +  Hash *entry = JSEmitter::createNamespaceEntry(name, parent, parent_mangled); +  Setattr(entry, "functions", NewString("")); +  Setattr(entry, "values", NewString("")); +  return entry; +} + +int JSCEmitter::emitNamespaces() { +  Iterator it; +  for (it = First(namespaces); it.item; it = Next(it)) { +    Hash *entry = it.item; +    String *name = Getattr(entry, NAME); +    String *name_mangled = Getattr(entry, NAME_MANGLED); +    String *parent_mangled = Getattr(entry, PARENT_MANGLED); +    String *functions = Getattr(entry, "functions"); +    String *variables = Getattr(entry, "values"); + +    // skip the global namespace which is given by the application + +    Template namespace_definition(getTemplate("jsc_nspace_declaration")); +    namespace_definition.replace("$jsglobalvariables", variables) +	.replace("$jsglobalfunctions", functions) +	.replace("$jsnspace", name_mangled) +	.replace("$jsmangledname", name_mangled) +	.pretty_print(f_wrap_cpp); + +    Template t_createNamespace(getTemplate("jsc_nspace_definition")); +    t_createNamespace.replace("$jsmangledname", name_mangled); +    Append(state.globals(CREATE_NAMESPACES), t_createNamespace.str()); + +    // Don't register 'exports' as namespace. It is return to the application. +    if (!Equal("exports", name)) { +      Template t_registerNamespace(getTemplate("jsc_nspace_registration")); +      t_registerNamespace.replace("$jsmangledname", name_mangled) +	  .replace("$jsname", name) +	  .replace("$jsparent", parent_mangled); +      Append(state.globals(REGISTER_NAMESPACES), t_registerNamespace.str()); +    } +  } + +  return SWIG_OK; +} + +JSEmitter *swig_javascript_create_JSCEmitter() { +  return new JSCEmitter(); +} + +/********************************************************************** + * V8: JSEmitter implementation for V8 engine + **********************************************************************/ + +class V8Emitter:public JSEmitter { + +public: +  V8Emitter(); + +  virtual ~ V8Emitter(); +  virtual int initialize(Node *n); +  virtual int dump(Node *n); +  virtual int close(); +  virtual int enterClass(Node *n); +  virtual int exitClass(Node *n); +  virtual int enterVariable(Node *n); +  virtual int exitVariable(Node *n); +  virtual int exitFunction(Node *n); + +protected: +  virtual void marshalInputArgs(Node *n, ParmList *parms, Wrapper *wrapper, MarshallingMode mode, bool is_member, bool is_static); +  virtual int emitNamespaces(); + +protected: +  /* built-in parts */ +  String *f_runtime; +  String *f_header; +  String *f_init; +  String *f_post_init; + +  /* part for class templates */ +  String *f_class_templates; + +  /* parts for initilizer */ +  String *f_init_namespaces; +  String *f_init_class_templates; +  String *f_init_wrappers; +  String *f_init_inheritance; +  String *f_init_class_instances; +  String *f_init_static_wrappers; +  String *f_init_register_classes; +  String *f_init_register_namespaces; + +  // the output cpp file +  File *f_wrap_cpp; + +  String *NULL_STR; +  String *VETO_SET; +  String *moduleName; + +}; + +V8Emitter::V8Emitter() +:  JSEmitter(JSEmitter::V8), NULL_STR(NewString("0")), VETO_SET(NewString("JS_veto_set_variable")) { +} + +V8Emitter::~V8Emitter() { +  Delete(NULL_STR); +  Delete(VETO_SET); +} + +int V8Emitter::initialize(Node *n) { +  JSEmitter::initialize(n); + +  moduleName = Getattr(n, "name"); + +  // Get the output file name +  String *outfile = Getattr(n, "outfile"); +  f_wrap_cpp = NewFile(outfile, "w", SWIG_output_files()); +  if (!f_wrap_cpp) { +    FileErrorDisplay(outfile); +    Exit(EXIT_FAILURE); +  } + +  f_runtime = NewString(""); +  f_header = NewString(""); +  f_class_templates = NewString(""); +  f_init = NewString(""); +  f_post_init = NewString(""); + +  f_init_namespaces = NewString(""); +  f_init_class_templates = NewString(""); +  f_init_wrappers = NewString(""); +  f_init_inheritance = NewString(""); +  f_init_class_instances = NewString(""); +  f_init_static_wrappers = NewString(""); +  f_init_register_classes = NewString(""); +  f_init_register_namespaces = NewString(""); + +  // note: this is necessary for built-in generation of SWIG runtime code +  Swig_register_filebyname("begin", f_wrap_cpp); +  Swig_register_filebyname("runtime", f_runtime); +  Swig_register_filebyname("header", f_header); +  Swig_register_filebyname("wrapper", f_wrappers); +  Swig_register_filebyname("init", f_init); +  Swig_register_filebyname("post-init", f_post_init); + +  state.globals(FORCE_CPP, NewString("1")); + +  Swig_banner(f_wrap_cpp); + +  Swig_obligatory_macros(f_runtime, "JAVASCRIPT"); + +  return SWIG_OK; +} + +int V8Emitter::dump(Node *n) { +  /* Get the module name */ +  String *module = Getattr(n, "name"); + +  Template initializer_define(getTemplate("js_initializer_define")); +  initializer_define.replace("$jsname", module).pretty_print(f_header); + +  SwigType_emit_type_table(f_runtime, f_wrappers); + +  Printv(f_wrap_cpp, f_runtime, "\n", 0); +  Printv(f_wrap_cpp, f_header, "\n", 0); +  Printv(f_wrap_cpp, f_class_templates, "\n", 0); +  Printv(f_wrap_cpp, f_wrappers, "\n", 0); + +  emitNamespaces(); + +  // compose the initializer function using a template +  // filled with sub-parts +  Template initializer(getTemplate("js_initializer")); +  initializer.replace("$jsname", moduleName) +      .replace("$jsv8nspaces", f_init_namespaces) +      .replace("$jsv8classtemplates", f_init_class_templates) +      .replace("$jsv8wrappers", f_init_wrappers) +      .replace("$jsv8inheritance", f_init_inheritance) +      .replace("$jsv8classinstances", f_init_class_instances) +      .replace("$jsv8staticwrappers", f_init_static_wrappers) +      .replace("$jsv8registerclasses", f_init_register_classes) +      .replace("$jsv8registernspaces", f_init_register_namespaces); +  Printv(f_init, initializer.str(), 0); + +  Printv(f_wrap_cpp, f_init, 0); + +  Printv(f_wrap_cpp, f_post_init, 0); + +  return SWIG_OK; +} + +int V8Emitter::close() { +  Delete(f_runtime); +  Delete(f_header); +  Delete(f_class_templates); +  Delete(f_init_namespaces); +  Delete(f_init_class_templates); +  Delete(f_init_wrappers); +  Delete(f_init_inheritance); +  Delete(f_init_class_instances); +  Delete(f_init_static_wrappers); +  Delete(f_init_register_classes); +  Delete(f_init_register_namespaces); +  Delete(f_init); +  Delete(f_post_init); +  Delete(f_wrap_cpp); +  return SWIG_OK; +} + +int V8Emitter::enterClass(Node *n) { +  JSEmitter::enterClass(n); + +  // emit declaration of a v8 class template +  Template t_decl_class(getTemplate("jsv8_declare_class_template")); +  t_decl_class.replace("$jsmangledname", state.clazz(NAME_MANGLED)) +      .trim() +      .pretty_print(f_class_templates); + +  return SWIG_OK; +} + +int V8Emitter::exitClass(Node *n) { +  if (GetFlag(state.clazz(), IS_ABSTRACT)) { +    Template t_veto_ctor(getTemplate("js_veto_ctor")); +    t_veto_ctor.replace("$jswrapper", state.clazz(CTOR)) +	.replace("$jsname", state.clazz(NAME)) +	.pretty_print(f_wrappers); +  } + +  /* Note: this makes sure that there is a swig_type added for this class */ +  String *clientData = NewString(""); +  Printf(clientData, "&%s_clientData", state.clazz(NAME_MANGLED)); + +  /* Note: this makes sure that there is a swig_type added for this class */ +  SwigType_remember_clientdata(state.clazz(TYPE_MANGLED), NewString("0")); + +  // emit definition of v8 class template +  Template t_def_class = getTemplate("jsv8_define_class_template"); +  t_def_class.replace("$jsmangledname", state.clazz(NAME_MANGLED)) +      .replace("$jsname", state.clazz(NAME)) +      .replace("$jsmangledtype", state.clazz(TYPE_MANGLED)) +      .replace("$jsdtor", state.clazz(DTOR)) +      .trim() +      .pretty_print(f_init_class_templates); + +  Template t_class_instance = getTemplate("jsv8_create_class_instance"); +  t_class_instance.replace("$jsname", state.clazz(NAME)) +      .replace("$jsmangledname", state.clazz(NAME_MANGLED)) +      .replace("$jsctor", state.clazz(CTOR)) +      .trim() +      .pretty_print(f_init_class_instances); + +  //  emit inheritance setup +  Node *baseClass = getBaseClass(n); +  if (baseClass) { +    String *base_name = Getattr(baseClass, "name"); + +    Template t_inherit = getTemplate("jsv8_inherit"); + +    String *base_name_mangled = SwigType_manglestr(base_name); +    t_inherit.replace("$jsmangledname", state.clazz(NAME_MANGLED)) +	.replace("$jsbaseclass", base_name_mangled) +	.trim() +	.pretty_print(f_init_inheritance); +    Delete(base_name_mangled); +  } +  //  emit registration of class template +  Template t_register = getTemplate("jsv8_register_class"); +  t_register.replace("$jsmangledname", state.clazz(NAME_MANGLED)) +      .replace("$jsname", state.clazz(NAME)) +      .replace("$jsparent", Getattr(state.clazz("nspace"), NAME_MANGLED)) +      .trim() +      .pretty_print(f_init_register_classes); + +  return SWIG_OK; +} + +int V8Emitter::enterVariable(Node *n) { +  JSEmitter::enterVariable(n); + +  state.variable(GETTER, NULL_STR); +  state.variable(SETTER, VETO_SET); + +  return SWIG_OK; +} + +int V8Emitter::exitVariable(Node *n) { +  if (GetFlag(n, "ismember")) { +    if (GetFlag(state.variable(), IS_STATIC) || Equal(Getattr(n, "nodeType"), "enumitem")) { +      Template t_register = getTemplate("jsv8_register_static_variable"); +      t_register.replace("$jsparent", state.clazz(NAME_MANGLED)) +	  .replace("$jsname", state.variable(NAME)) +	  .replace("$jsgetter", state.variable(GETTER)) +	  .replace("$jssetter", state.variable(SETTER)) +	  .trim() +	  .pretty_print(f_init_static_wrappers); +    } else { +      Template t_register = getTemplate("jsv8_register_member_variable"); +      t_register.replace("$jsmangledname", state.clazz(NAME_MANGLED)) +	  .replace("$jsname", state.variable(NAME)) +	  .replace("$jsgetter", state.variable(GETTER)) +	  .replace("$jssetter", state.variable(SETTER)) +	  .trim() +	  .pretty_print(f_init_wrappers); +    } +  } else { +    // Note: a global variable is treated like a static variable +    //       with the parent being a nspace object (instead of class object) +    Template t_register = getTemplate("jsv8_register_static_variable"); +    t_register.replace("$jsparent", Getattr(current_namespace, NAME_MANGLED)) +	.replace("$jsname", state.variable(NAME)) +	.replace("$jsgetter", state.variable(GETTER)) +	.replace("$jssetter", state.variable(SETTER)) +	.trim() +	.pretty_print(f_init_wrappers); +  } + +  return SWIG_OK; +} + +int V8Emitter::exitFunction(Node *n) { +  bool is_member = GetFlag(n, "ismember") != 0 || GetFlag(n, "feature:extend") != 0; + +  // create a dispatcher for overloaded functions +  bool is_overloaded = GetFlag(n, "sym:overloaded") != 0; +  if (is_overloaded) { +    if (!Getattr(n, "sym:nextSibling")) { +      //state.function(WRAPPER_NAME, Swig_name_wrapper(Getattr(n, "name"))); +      emitFunctionDispatcher(n, is_member); +    } else { +      //don't register wrappers of overloaded functions in function tables +      return SWIG_OK; +    } +  } +  // register the function at the specific context +  if (is_member) { +    if (GetFlag(state.function(), IS_STATIC)) { +      Template t_register = getTemplate("jsv8_register_static_function"); +      t_register.replace("$jsparent", state.clazz(NAME_MANGLED)) +	  .replace("$jsname", state.function(NAME)) +	  .replace("$jswrapper", state.function(WRAPPER_NAME)) +	  .trim() +	  .pretty_print(f_init_static_wrappers); +    } else { +      Template t_register = getTemplate("jsv8_register_member_function"); +      t_register.replace("$jsmangledname", state.clazz(NAME_MANGLED)) +	  .replace("$jsname", state.function(NAME)) +	  .replace("$jswrapper", state.function(WRAPPER_NAME)) +	  .trim() +	  .pretty_print(f_init_wrappers); +    } +  } else { +    // Note: a global function is treated like a static function +    //       with the parent being a nspace object instead of class object +    Template t_register = getTemplate("jsv8_register_static_function"); +    t_register.replace("$jsparent", Getattr(current_namespace, NAME_MANGLED)) +	.replace("$jsname", state.function(NAME)) +	.replace("$jswrapper", state.function(WRAPPER_NAME)) +	.trim() +	.pretty_print(f_init_static_wrappers); +  } + +  return SWIG_OK; +} + +void V8Emitter::marshalInputArgs(Node *n, ParmList *parms, Wrapper *wrapper, MarshallingMode mode, bool is_member, bool is_static) { +  Parm *p; +  String *tm; + +  int startIdx = 0; +  if (is_member && !is_static && mode != Ctor) { +    startIdx = 1; +  } +  // store number of arguments for argument checks +  int num_args = emit_num_arguments(parms) - startIdx; +  String *argcount = NewString(""); +  Printf(argcount, "%d", num_args); +  Setattr(n, ARGCOUNT, argcount); + +  int i = 0; +  for (p = parms; p; i++) { +    String *arg = NewString(""); +    String *type = Getattr(p, "type"); + +    // ignore varargs +    if (SwigType_isvarargs(type)) +      break; + +    switch (mode) { +    case Getter: +      if (is_member && !is_static && i == 0) { +	Printv(arg, "info.Holder()", 0); +      } else { +	Printf(arg, "args[%d]", i - startIdx); +      } +      break; +    case Function: +      if (is_member && !is_static && i == 0) { +	Printv(arg, "args.Holder()", 0); +      } else { +	Printf(arg, "args[%d]", i - startIdx); +      } +      break; +    case Setter: +      if (is_member && !is_static && i == 0) { +	Printv(arg, "info.Holder()", 0); +      } else { +	Printv(arg, "value", 0); +      } +      break; +    case Ctor: +      Printf(arg, "args[%d]", i); +      break; +    default: +      Printf(stderr, "Illegal MarshallingMode."); +      Exit(EXIT_FAILURE); +    } + +    tm = emitInputTypemap(n, p, wrapper, arg); +    Delete(arg); + +    if (tm) { +      p = Getattr(p, "tmap:in:next"); +    } else { +      p = nextSibling(p); +    } +  } +} + +int V8Emitter::emitNamespaces() { +  Iterator it; +  for (it = First(namespaces); it.item; it = Next(it)) { +    Hash *entry = it.item; +    String *name = Getattr(entry, NAME); +    String *name_mangled = Getattr(entry, NAME_MANGLED); +    String *parent = Getattr(entry, PARENT); +    String *parent_mangled = Getattr(entry, PARENT_MANGLED); + +    bool do_create = true; +    bool do_register = true; + +    if (Equal(parent, "")) { +      do_register = false; +    } +    // Note: 'exports' is by convention the name of the object where +    // globals are stored into +    if (Equal(name, "exports")) { +      do_create = false; +    } + +    if (do_create) { +      // create namespace object and register it to the parent scope +      Template t_create_ns = getTemplate("jsv8_create_namespace"); +      t_create_ns.replace("$jsmangledname", name_mangled) +	  .trim() +	  .pretty_print(f_init_namespaces); +    } + +    if (do_register) { +      Template t_register_ns = getTemplate("jsv8_register_namespace"); +      t_register_ns.replace("$jsmangledname", name_mangled) +	  .replace("$jsname", name) +	  .replace("$jsparent", parent_mangled) +	  .trim(); + +      // prepend in order to achieve reversed order of registration statements +      String *tmp_register_stmt = NewString(""); +      t_register_ns.pretty_print(tmp_register_stmt); +      Insert(f_init_register_namespaces, 0, tmp_register_stmt); +      Delete(tmp_register_stmt); +    } +  } + +  return SWIG_OK; +} + +JSEmitter *swig_javascript_create_V8Emitter() { +  return new V8Emitter(); +} + +/********************************************************************** + * Helper implementations + **********************************************************************/ + +JSEmitterState::JSEmitterState() +:  globalHash(NewHash()) { +  // initialize sub-hashes +  Setattr(globalHash, "class", NewHash()); +  Setattr(globalHash, "function", NewHash()); +  Setattr(globalHash, "variable", NewHash()); +} + +JSEmitterState::~JSEmitterState() { +  Delete(globalHash); +} + +DOH *JSEmitterState::getState(const char *key, bool new_key) { +  if (new_key) { +    Hash *hash = NewHash(); +    Setattr(globalHash, key, hash); +  } +  return Getattr(globalHash, key); +} + +DOH *JSEmitterState::globals() { +  return globalHash; +} + +DOH *JSEmitterState::globals(const char *key, DOH *initial) { +  if (initial != 0) { +    Setattr(globalHash, key, initial); +  } +  return Getattr(globalHash, key); +} + +DOH *JSEmitterState::clazz(bool new_key) { +  return getState("class", new_key); +} + +DOH *JSEmitterState::clazz(const char *key, DOH *initial) { +  DOH *c = clazz(); +  if (initial != 0) { +    Setattr(c, key, initial); +  } +  return Getattr(c, key); +} + +DOH *JSEmitterState::function(bool new_key) { +  return getState("function", new_key); +} + +DOH *JSEmitterState::function(const char *key, DOH *initial) { +  DOH *f = function(); +  if (initial != 0) { +    Setattr(f, key, initial); +  } +  return Getattr(f, key); +} + +DOH *JSEmitterState::variable(bool new_key) { +  return getState("variable", new_key); +} + +DOH *JSEmitterState::variable(const char *key, DOH *initial) { +  DOH *v = variable(); +  if (initial != 0) { +    Setattr(v, key, initial); +  } +  return Getattr(v, key); +} + +/*static*/ +int JSEmitterState::IsSet(DOH *val) { +  if (!val) { +    return 0; +  } else { +    const char *cval = Char(val); +    if (!cval) +      return 0; +    return (strcmp(cval, "0") != 0) ? 1 : 0; +  } +} + +/* ----------------------------------------------------------------------------- + * Template::Template() :  creates a Template class for given template code + * ----------------------------------------------------------------------------- */ + +Template::Template(const String *code_) { + +  if (!code_) { +    Printf(stdout, "Template code was null. Illegal input for template."); +    Exit(EXIT_FAILURE); +  } +  code = NewString(code_); +  templateName = NewString(""); +} + +Template::Template(const String *code_, const String *templateName_) { + +  if (!code_) { +    Printf(stdout, "Template code was null. Illegal input for template."); +    Exit(EXIT_FAILURE); +  } + +  code = NewString(code_); +  templateName = NewString(templateName_); +} + + +/* ----------------------------------------------------------------------------- + * Template::~Template() :  cleans up of Template. + * ----------------------------------------------------------------------------- */ + +Template::~Template() { +  Delete(code); +  Delete(templateName); +} + +/* ----------------------------------------------------------------------------- + * String* Template::str() :  retrieves the current content of the template. + * ----------------------------------------------------------------------------- */ + +String *Template::str() { +  if (js_template_enable_debug) { +    String *pre_code = NewString(""); +    String *post_code = NewString(""); +    String *debug_code = NewString(""); +    Printf(pre_code, "/* begin fragment(\"%s\") */", templateName); +    Printf(post_code, "/* end fragment(\"%s\") */", templateName); +    Printf(debug_code, "%s\n%s\n%s\n", pre_code, code, post_code); + +    Delete(code); +    Delete(pre_code); +    Delete(post_code); + +    code = debug_code; +  } +  return code; +} + +Template & Template::trim() { +  const char *str = Char(code); +  if (str == 0) +    return *this; + +  int length = Len(code); +  if (length == 0) +    return *this; + +  int idx; +  for (idx = 0; idx < length; ++idx) { +    if (str[idx] != ' ' && str[idx] != '\t' && str[idx] != '\r' && str[idx] != '\n') +      break; +  } +  int start_pos = idx; + +  for (idx = length - 1; idx >= start_pos; --idx) { +    if (str[idx] != ' ' && str[idx] != '\t' && str[idx] != '\r' && str[idx] != '\n') +      break; +  } +  int end_pos = idx; + +  int new_length = end_pos - start_pos + 1; +  char *newstr = new char[new_length + 1]; +  memcpy(newstr, str + start_pos, new_length); +  newstr[new_length] = 0; + +  Delete(code); +  code = NewString(newstr); +  delete[]newstr; + +  return *this; +} + +/* ----------------------------------------------------------------------------- + * Template&  Template::replace(const String* pattern, const String* repl) : + * + *  replaces all occurrences of a given pattern with a given replacement. + * + *  - pattern:  the pattern to be replaced + *  - repl:     the replacement string + *  - returns a reference to the Template to allow chaining of methods. + * ----------------------------------------------------------------------------- */ + +Template & Template::replace(const String *pattern, const String *repl) { +  Replaceall(code, pattern, repl); +  return *this; +} + +Template & Template::print(DOH *doh) { +  Printv(doh, str(), 0); +  return *this; +} + +Template & Template::pretty_print(DOH *doh) { +  Wrapper_pretty_print(str(), doh); +  return *this; +} + +Template::Template(const Template & t) { +  code = NewString(t.code); +  templateName = NewString(t.templateName); +} + +void Template::operator=(const Template & t) { +  Delete(code); +  Delete(templateName); +  code = NewString(t.code); +  templateName = NewString(t.templateName); +} diff --git a/contrib/tools/swig/Source/Modules/lang.cxx b/contrib/tools/swig/Source/Modules/lang.cxx new file mode 100644 index 00000000000..1e10e51d675 --- /dev/null +++ b/contrib/tools/swig/Source/Modules/lang.cxx @@ -0,0 +1,3902 @@ +/* ----------------------------------------------------------------------------- + * This file is part of SWIG, which is licensed as a whole under version 3  + * (or any later version) of the GNU General Public License. Some additional + * terms also apply to certain portions of SWIG. The full details of the SWIG + * license and copyrights can be found in the LICENSE and COPYRIGHT files + * included with the SWIG source code as distributed by the SWIG developers + * and at https://www.swig.org/legal.html. + * + * lang.cxx + * + * Language base class functions.  Default C++ handling is also implemented here. + * ----------------------------------------------------------------------------- */ + +#include "swigmod.h" +#include "cparse.h" +#include <ctype.h> + +/* default mode settings */ +static int director_mode = 0; +static int director_protected_mode = 1; +static int all_protected_mode = 0; +static int naturalvar_mode = 0; +Language *Language::this_ = 0; + +/* Set director_protected_mode */ +void Wrapper_director_mode_set(int flag) { +  director_mode = flag; +} + +void Wrapper_director_protected_mode_set(int flag) { +  director_protected_mode = flag; +} + +void Wrapper_all_protected_mode_set(int flag) { +  all_protected_mode = flag; +} + +void Wrapper_naturalvar_mode_set(int flag) { +  naturalvar_mode = flag; +} + +extern "C" { +  int Swig_director_mode() { +    return director_mode; +  } +  int Swig_director_protected_mode() { +    return director_protected_mode; +  } +  int Swig_all_protected_mode() { +    return all_protected_mode; +  } +  void Language_replace_special_variables(String *method, String *tm, Parm *parm) { +    Language::instance()->replaceSpecialVariables(method, tm, parm); +  } +} + +/* Some status variables used during parsing */ +static int InClass = 0; /* Parsing C++ or not */ +static String *ClassName = 0;	/* This is the real name of the current class */ +static String *EnumClassName = 0; /* Enum class name */ +static String *ClassPrefix = 0;	/* Class prefix */ +static String *EnumClassPrefix = 0; /* Prefix for strongly typed enums (including ClassPrefix) */ +static String *NSpace = 0;	/* Namespace for the nspace feature */ +static String *ClassType = 0;	/* Fully qualified type name to use */ +static String *DirectorClassName = 0;	/* Director name of the current class */ +int Abstract = 0; +int ImportMode = 0; +int IsVirtual = 0; +static String *AttributeFunctionGet = 0; +static String *AttributeFunctionSet = 0; +static Node *CurrentClass = 0; +int line_number = 0; +String *input_file = 0; +int SmartPointer = 0; +static Hash *classhash; + +extern int GenerateDefault; +extern int ForceExtern; +extern int AddExtern; +extern "C" { +  extern int UseWrapperSuffix; +} + +/* import modes */ + +#define  IMPORT_MODE     1 + +/* ---------------------------------------------------------------------- + * Dispatcher::emit_one() + * + * Dispatch a single node + * ---------------------------------------------------------------------- */ + +int Dispatcher::emit_one(Node *n) { +  int ret = SWIG_OK; + +  char *tag = Char(nodeType(n)); +  if (!tag) { +    /* Printf(stderr,"SWIG: Fatal internal error. Malformed parse tree +       node!\n"); */ +    return SWIG_OK; +  } + +  /* Do not proceed if marked with an error */ + +  if (Getattr(n, "error")) +    return SWIG_OK; + +  /* Look for warnings */ +  String *wrn = Getattr(n, "feature:warnfilter"); +  if (wrn) +    Swig_warnfilter(wrn, 1); + +  /* ============================================================ +   * C/C++ parsing +   * ============================================================ */ + +  if (strcmp(tag, "extern") == 0) { +    ret = externDeclaration(n); +  } else if (strcmp(tag, "cdecl") == 0) { +    ret = cDeclaration(n); +  } else if (strcmp(tag, "enum") == 0) { +    ret = enumDeclaration(n); +  } else if (strcmp(tag, "enumitem") == 0) { +    ret = enumvalueDeclaration(n); +  } else if (strcmp(tag, "enumforward") == 0) { +    ret = enumforwardDeclaration(n); +  } else if (strcmp(tag, "class") == 0) { +    ret = classDeclaration(n); +  } else if (strcmp(tag, "classforward") == 0) { +    ret = classforwardDeclaration(n); +  } else if (strcmp(tag, "constructor") == 0) { +    ret = constructorDeclaration(n); +  } else if (strcmp(tag, "destructor") == 0) { +    ret = destructorDeclaration(n); +  } else if (strcmp(tag, "access") == 0) { +    ret = accessDeclaration(n); +  } else if (strcmp(tag, "using") == 0) { +    ret = usingDeclaration(n); +  } else if (strcmp(tag, "namespace") == 0) { +    ret = namespaceDeclaration(n); +  } else if (strcmp(tag, "template") == 0) { +    ret = templateDeclaration(n); +  } else if (strcmp(tag, "lambda") == 0) { +    ret = lambdaDeclaration(n); +  } + +  /* =============================================================== +   *  SWIG directives +   * =============================================================== */ + +  else if (strcmp(tag, "top") == 0) { +    ret = top(n); +  } else if (strcmp(tag, "extend") == 0) { +    ret = extendDirective(n); +  } else if (strcmp(tag, "apply") == 0) { +    ret = applyDirective(n); +  } else if (strcmp(tag, "clear") == 0) { +    ret = clearDirective(n); +  } else if (strcmp(tag, "constant") == 0) { +    ret = constantDirective(n); +  } else if (strcmp(tag, "fragment") == 0) { +    ret = fragmentDirective(n); +  } else if (strcmp(tag, "import") == 0) { +    ret = importDirective(n); +  } else if (strcmp(tag, "include") == 0) { +    ret = includeDirective(n); +  } else if (strcmp(tag, "insert") == 0) { +    ret = insertDirective(n); +  } else if (strcmp(tag, "module") == 0) { +    ret = moduleDirective(n); +  } else if (strcmp(tag, "native") == 0) { +    ret = nativeDirective(n); +  } else if (strcmp(tag, "pragma") == 0) { +    ret = pragmaDirective(n); +  } else if (strcmp(tag, "typemap") == 0) { +    ret = typemapDirective(n); +  } else if (strcmp(tag, "typemapcopy") == 0) { +    ret = typemapcopyDirective(n); +  } else if (strcmp(tag, "typemapitem") == 0) { +    ret = typemapitemDirective(n); +  } else if (strcmp(tag, "types") == 0) { +    ret = typesDirective(n); +  } else { +    Swig_error(input_file, line_number, "Unrecognized parse tree node type '%s'\n", tag); +    ret = SWIG_ERROR; +  } +  if (wrn) +    Swig_warnfilter(wrn, 0); +  return ret; +} + +/* ---------------------------------------------------------------------- + * Dispatcher::emit_children() + * + * Emit all children that match the given type. type = 0 means all types. + * ---------------------------------------------------------------------- */ + +int Dispatcher::emit_children(Node *n) { +  Node *c; +  char *eo = Char(Getattr(n, "feature:emitonlychildren")); +  for (c = firstChild(n); c; c = nextSibling(c)) { +    if (eo) { +      const char *tag = Char(nodeType(c)); +      if (strcmp(tag, "cdecl") == 0) { +	if (checkAttribute(c, "storage", "typedef")) +	  tag = "typedef"; +      } +      if (strstr(eo, tag) == 0) { +	continue; +      } +    } +    emit_one(c); +  } +  return SWIG_OK; +} + + +/* Stubs for dispatcher class.  We don't do anything by default---up to derived class +   to fill in traversal code */ + +int Dispatcher::defaultHandler(Node *) { +  return SWIG_OK; +} +int Dispatcher::extendDirective(Node *n) { +  return defaultHandler(n); +} +int Dispatcher::applyDirective(Node *n) { +  return defaultHandler(n); +} +int Dispatcher::clearDirective(Node *n) { +  return defaultHandler(n); +} +int Dispatcher::constantDirective(Node *n) { +  return defaultHandler(n); +} +int Dispatcher::fragmentDirective(Node *n) { +  return defaultHandler(n); +} +int Dispatcher::importDirective(Node *n) { +  return defaultHandler(n); +} +int Dispatcher::includeDirective(Node *n) { +  return defaultHandler(n); +} +int Dispatcher::insertDirective(Node *n) { +  return defaultHandler(n); +} +int Dispatcher::moduleDirective(Node *n) { +  return defaultHandler(n); +} +int Dispatcher::nativeDirective(Node *n) { +  return defaultHandler(n); +} +int Dispatcher::pragmaDirective(Node *n) { +  return defaultHandler(n); +} +int Dispatcher::typemapDirective(Node *n) { +  return defaultHandler(n); +} +int Dispatcher::typemapitemDirective(Node *n) { +  return defaultHandler(n); +} +int Dispatcher::typemapcopyDirective(Node *n) { +  return defaultHandler(n); +} +int Dispatcher::typesDirective(Node *n) { +  return defaultHandler(n); +} +int Dispatcher::cDeclaration(Node *n) { +  return defaultHandler(n); +} +int Dispatcher::externDeclaration(Node *n) { +  return defaultHandler(n); +} +int Dispatcher::enumDeclaration(Node *n) { +  return defaultHandler(n); +} +int Dispatcher::enumvalueDeclaration(Node *n) { +  return defaultHandler(n); +} +int Dispatcher::enumforwardDeclaration(Node *n) { +  return defaultHandler(n); +} +int Dispatcher::classDeclaration(Node *n) { +  return defaultHandler(n); +} +int Dispatcher::templateDeclaration(Node *n) { +  return defaultHandler(n); +} +int Dispatcher::lambdaDeclaration(Node *n) { +  return defaultHandler(n); +} +int Dispatcher::classforwardDeclaration(Node *n) { +  return defaultHandler(n); +} +int Dispatcher::constructorDeclaration(Node *n) { +  return defaultHandler(n); +} +int Dispatcher::destructorDeclaration(Node *n) { +  return defaultHandler(n); +} +int Dispatcher::accessDeclaration(Node *n) { +  return defaultHandler(n); +} +int Dispatcher::usingDeclaration(Node *n) { +  return defaultHandler(n); +} +int Dispatcher::namespaceDeclaration(Node *n) { +  return defaultHandler(n); +} + +/* Allocators */ +Language::Language(): +none_comparison(NewString("$arg != 0")), +director_ctor_code(NewString("")), +director_prot_ctor_code(0), +symtabs(NewHash()), +overloading(0), +multiinput(0), +cplus_runtime(0), +directors(0) { +  symbolAddScope(""); // create top level/global symbol table scope +  argc_template_string = NewString("argc"); +  argv_template_string = NewString("argv[%d]"); + +  /* Default director constructor code, passed to Swig_ConstructorToFunction */ +  Printv(director_ctor_code, "if ( $comparison ) { /* subclassed */\n", "  $director_new \n", "} else {\n", "  $nondirector_new \n", "}\n", NIL); + +  /* +     Default director 'protected' constructor code, disabled by +     default. Each language that needs it, has to define it. +   */ +  director_prot_ctor_code = 0; +  director_multiple_inheritance = 1; +  director_language = 0; +  assert(!this_); +  this_ = this; + +  doxygenTranslator = NULL; +} + +Language::~Language() { +  Delete(symtabs); +  Delete(director_ctor_code); +  Delete(none_comparison); +  this_ = 0; +} + +  /* ----------------------------------------------------------------------------- +   * directorClassName() +   * ----------------------------------------------------------------------------- */ + +  String *Language::directorClassName(Node *n) { +    String *dirclassname; +    String *nspace = NewString(Getattr(n, "sym:nspace")); +    const char *attrib = "director:classname"; +    String *classname = getClassPrefix(); + +    Replace(nspace, NSPACE_SEPARATOR, "_", DOH_REPLACE_ANY); +    if (Len(nspace) > 0) +      dirclassname = NewStringf("SwigDirector_%s_%s", nspace, classname); +    else +      dirclassname = NewStringf("SwigDirector_%s", classname); +    Setattr(n, attrib, dirclassname); + +    Delete(nspace); +    return dirclassname; +  } + +/* ---------------------------------------------------------------------- +   emit_one() +   ---------------------------------------------------------------------- */ + +int Language::emit_one(Node *n) { +  int ret; +  int oldext; +  if (!n) +    return SWIG_OK; + +  if (GetFlag(n, "feature:ignore") +      && !Getattr(n, "feature:onlychildren")) +    return SWIG_OK; + +  oldext = Extend; +  if (Getattr(n, "feature:extend")) +    Extend = 1; + +  line_number = Getline(n); +  input_file = Getfile(n); + +  /* +     symtab = Getattr(n,"symtab"); +     if (symtab) { +     symtab = Swig_symbol_setscope(symtab); +     } +   */ +  ret = Dispatcher::emit_one(n); +  /* +     if (symtab) { +     Swig_symbol_setscope(symtab); +     } +   */ +  Extend = oldext; +  return ret; +} + + +static Parm *nonvoid_parms(Parm *p) { +  if (p) { +    SwigType *t = Getattr(p, "type"); +    if (SwigType_type(t) == T_VOID) +      return 0; +  } +  return p; +} + +/* ----------------------------------------------------------------------------- + * cplus_value_type() + * + * Returns the alternative value type needed in C++ for class value + * types. When swig is not sure about using a plain $ltype value, + * since the class doesn't have a default constructor, or it can't be + * assigned, you will get back 'SwigValueWrapper<type >'. + * + * ----------------------------------------------------------------------------- */ + +SwigType *cplus_value_type(SwigType *t) { +  return SwigType_alttype(t, 0); +} + +static Node *first_nontemplate(Node *n) { +  while (n) { +    if (Strcmp(nodeType(n), "template") != 0) +      return n; +    n = Getattr(n, "sym:nextSibling"); +  } +  return n; +} + + + +/* -------------------------------------------------------------------------- + * swig_pragma() + * + * Handle swig pragma directives.   + * -------------------------------------------------------------------------- */ + +void swig_pragma(char *lang, char *name, char *value) { +  if (strcmp(lang, "swig") == 0) { +    if ((strcmp(name, "make_default") == 0) || ((strcmp(name, "makedefault") == 0))) { +      GenerateDefault = 1; +    } else if ((strcmp(name, "no_default") == 0) || ((strcmp(name, "nodefault") == 0))) { +      Swig_warning(WARN_DEPRECATED_NODEFAULT, "SWIG", 1, "dangerous, use %%nodefaultctor, %%nodefaultdtor instead.\n"); +      GenerateDefault = 0; +    } else if (strcmp(name, "attributefunction") == 0) { +      String *nvalue = NewString(value); +      char *s = strchr(Char(nvalue), ':'); +      if (!s) { +	Swig_error(input_file, line_number, "Bad value for attributefunction. Expected \"fmtget:fmtset\".\n"); +      } else { +	*s = 0; +	AttributeFunctionGet = NewString(Char(nvalue)); +	AttributeFunctionSet = NewString(s + 1); +      } +      Delete(nvalue); +    } else if (strcmp(name, "noattributefunction") == 0) { +      AttributeFunctionGet = 0; +      AttributeFunctionSet = 0; +    } +  } +} + +/* -------------------------------------------------------------------------- + * Language::use_naturalvar_mode() + * + * Determine whether to use const ref typemaps instead of pointer typemaps + * for variable access. + * -------------------------------------------------------------------------- */ +int Language::use_naturalvar_mode(Node *n) const { +  if (Getattr(n, "unnamed")) +    return 0; + +  // The naturalvar feature can be attached to either the variable name or the variable's type +  // naturalvar on the variable name is more specific and overrides naturalvar on the variable's type +  String *naturalvar = Getattr(n, "feature:naturalvar"); +  bool explicitly_off = naturalvar && Strcmp(naturalvar, "0") == 0; +  int nvar = GetFlag(n, "feature:naturalvar"); + +  if (!explicitly_off && !nvar) { +    /* look for feature in the class */ +    SwigType *ty = Getattr(n, "type"); +    SwigType *fullty = SwigType_typedef_resolve_all(ty); +    if (SwigType_isclass(fullty)) { +      SwigType *tys = SwigType_strip_qualifiers(fullty); +      if (!CPlusPlus) { +	Replaceall(tys, "struct ", ""); +	Replaceall(tys, "union ", ""); +	Replaceall(tys, "class ", ""); +      } +      Node *typenode = Swig_symbol_clookup(tys, 0); +      if (typenode) { +	naturalvar = Getattr(typenode, "feature:naturalvar"); +	explicitly_off = naturalvar && Strcmp(naturalvar, "0") == 0; +	nvar = nvar || GetFlag(typenode, "feature:naturalvar"); +      } +      Delete(tys); +    } +    Delete(fullty); +  } +  nvar = nvar || naturalvar_mode; +  return explicitly_off ? 0 : nvar ? CWRAP_NATURAL_VAR : 0; +} + +/* ---------------------------------------------------------------------- + * Language::top()   - Top of parsing tree  + * ---------------------------------------------------------------------- */ + +int Language::top(Node *n) { +  Node *mod = Getattr(n, "module"); +  if (mod) { +    Node *options = Getattr(mod, "options"); +    if (options) { +      if (Getattr(options, "naturalvar")) { +	naturalvar_mode = 1; +      } +    } +  } +  classhash = Getattr(n, "classes"); +  return emit_children(n); +} + +/* ---------------------------------------------------------------------- + * Language::extendDirective() + * ---------------------------------------------------------------------- */ + +int Language::extendDirective(Node *n) { +  save_value<int> oldam(Extend, CWRAP_EXTEND); +  save_value<AccessMode> oldmode(cplus_mode, PUBLIC); +  emit_children(n); +  return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::applyDirective() + * ---------------------------------------------------------------------- */ + +int Language::applyDirective(Node *n) { + +  Parm *pattern = Getattr(n, "pattern"); +  Node *c = firstChild(n); +  while (c) { +    Parm *apattern = Getattr(c, "pattern"); +    if (ParmList_len(pattern) != ParmList_len(apattern)) { +      Swig_error(input_file, line_number, "Can't apply (%s) to (%s).  Number of arguments don't match.\n", ParmList_str(pattern), ParmList_str(apattern)); +    } else { +      if (!Swig_typemap_apply(pattern, apattern)) { +	Swig_warning(WARN_TYPEMAP_APPLY_UNDEF, input_file, line_number, "Can't apply (%s). No typemaps are defined.\n", ParmList_str(pattern)); +      } +    } +    c = nextSibling(c); +  } +  return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::clearDirective() + * ---------------------------------------------------------------------- */ + +int Language::clearDirective(Node *n) { +  Node *p; +  for (p = firstChild(n); p; p = nextSibling(p)) { +    ParmList *pattern = Getattr(p, "pattern"); +    Swig_typemap_clear_apply(pattern); +  } +  return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::constantDirective() + * ---------------------------------------------------------------------- */ + +int Language::constantDirective(Node *n) { + +  if (CurrentClass && (cplus_mode != PUBLIC)) +    return SWIG_NOWRAP; + +  if (!GetFlag(n, "feature:allowexcept")) { +    UnsetFlag(n, "feature:except"); +  } +  if (Getattr(n, "feature:exceptvar")) { +    Setattr(n, "feature:except", Getattr(n, "feature:exceptvar")); +  } + +  if (!ImportMode) { +    Swig_require("constantDirective", n, "name", "?value", NIL); +    String *name = Getattr(n, "name"); +    String *value = Getattr(n, "value"); +    if (!value) { +      value = Copy(name); +    } else { +      /*      if (checkAttribute(n,"type","char")) { +         value = NewString(value); +         } else { +         value = NewStringf("%(escape)s", value); +         } +       */ +      Setattr(n, "rawvalue", value); +      value = NewStringf("%(escape)s", value); +      if (!Len(value)) +	Append(value, "\\0"); +      /*      Printf(stdout,"'%s' = '%s'\n", name, value); */ +    } +    Setattr(n, "value", value); +    this->constantWrapper(n); +    Swig_restore(n); +    return SWIG_OK; +  } +  return SWIG_NOWRAP; +} + +/* ---------------------------------------------------------------------- + * Language::fragmentDirective() + * ---------------------------------------------------------------------- */ + +int Language::fragmentDirective(Node *n) { +  if (!(Getattr(n, "emitonly") && ImportMode)) +    Swig_fragment_register(n); +  return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::importDirective() + * ---------------------------------------------------------------------- */ + +int Language::importDirective(Node *n) { +  int oldim = ImportMode; +  ImportMode = IMPORT_MODE; +  emit_children(n); +  ImportMode = oldim; +  return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::includeDirective() + * ---------------------------------------------------------------------- */ + +int Language::includeDirective(Node *n) { +  emit_children(n); +  return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::insertDirective() + * ---------------------------------------------------------------------- */ + +int Language::insertDirective(Node *n) { +  /* %insert directive */ +  if ((!ImportMode) || Getattr(n, "generated")) { +    String *code = Getattr(n, "code"); +    String *section = Getattr(n, "section"); +    File *f = 0; +    if (!section) {		/* %{ ... %} */ +      f = Swig_filebyname("header"); +    } else { +      f = Swig_filebyname(section); +    } +    if (f) { +      Printf(f, "%s\n", code); +    } else { +      Swig_error(input_file, line_number, "Unknown target '%s' for %%insert directive.\n", section); +    } +    return SWIG_OK; +  } else { +    return SWIG_NOWRAP; +  } +} + +/* ---------------------------------------------------------------------- + * Language::moduleDirective() + * ---------------------------------------------------------------------- */ + +int Language::moduleDirective(Node *n) { +  (void) n; +  /* %module directive */ +  return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::nativeDirective() + * ---------------------------------------------------------------------- */ + +int Language::nativeDirective(Node *n) { +  if (!ImportMode) { +    return nativeWrapper(n); +  } else { +    return SWIG_NOWRAP; +  } +} + +/* ---------------------------------------------------------------------- + * Language::pragmaDirective() + * ---------------------------------------------------------------------- */ + +int Language::pragmaDirective(Node *n) { +  /* %pragma directive */ +  if (!ImportMode) { +    String *lan = Getattr(n, "lang"); +    String *name = Getattr(n, "name"); +    String *value = Getattr(n, "value"); +    swig_pragma(Char(lan), Char(name), Char(value)); +    /*  pragma(Char(lan),Char(name),Char(value)); */ +    return SWIG_OK; +  } +  return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::typemapDirective() + * ---------------------------------------------------------------------- */ + +int Language::typemapDirective(Node *n) { +  /* %typemap directive */ +  String *method = Getattr(n, "method"); +  String *code = Getattr(n, "code"); +  Parm *kwargs = Getattr(n, "kwargs"); +  Node *items = firstChild(n); +  static int nameerror = 0; + + +  if (code && (Strstr(code, "$source") || (Strstr(code, "$target")))) { +    Swig_error(Getfile(n), Getline(n), "Obsolete typemap feature ($source/$target).\n"); +    if (!nameerror) { +      Swig_error(Getfile(n), Getline(n), "The use of $source and $target in a typemap declaration is no longer supported.\n\ +For typemaps related to argument input (in,ignore,default,arginit,check), replace\n\ +$source by $input and $target by $1.   For typemaps related to return values (out,\n\ +argout,ret,except), replace $source by $1 and $target by $result.  See the file\n\ +Doc/Manual/Typemaps.html for complete details.\n"); +      nameerror = 1; +    } +  } + +  if (Strcmp(method, "except") == 0) { +    Swig_warning(WARN_DEPRECATED_EXCEPT_TM, Getfile(n), Getline(n), "%%typemap(except) is deprecated. Use the %%exception directive.\n"); +  } + +  if (Strcmp(method, "in") == 0) { +    Hash *k; +    k = kwargs; +    while (k) { +      if (checkAttribute(k, "name", "numinputs")) { +	if (!multiinput && (GetInt(k, "value") > 1)) { +	  Swig_error(Getfile(n), Getline(n), "Multiple-input typemaps (numinputs > 1) not supported by this target language module.\n"); +	  return SWIG_ERROR; +	} +	break; +      } +      k = nextSibling(k); +    } +    if (!k) { +      k = NewHash(); +      Setattr(k, "name", "numinputs"); +      Setattr(k, "value", "1"); +      set_nextSibling(k, kwargs); +      Setattr(n, "kwargs", k); +      kwargs = k; +    } +  } + +  if (Strcmp(method, "ignore") == 0) { +    Swig_warning(WARN_DEPRECATED_IGNORE_TM, Getfile(n), Getline(n), "%%typemap(ignore) has been replaced by %%typemap(in,numinputs=0).\n"); + +    Clear(method); +    Append(method, "in"); +    Hash *k = NewHash(); +    Setattr(k, "name", "numinputs"); +    Setattr(k, "value", "0"); +    set_nextSibling(k, kwargs); +    Setattr(n, "kwargs", k); +    kwargs = k; +  } + +  /* Replace $descriptor() macros */ + +  if (code) { +    Setfile(code, Getfile(n)); +    Setline(code, Getline(n)); +    Swig_cparse_replace_descriptor(code); +  } + +  while (items) { +    Parm *pattern = Getattr(items, "pattern"); +    Parm *parms = Getattr(items, "parms"); + +    if (code) { +      Swig_typemap_register(method, pattern, code, parms, kwargs); +    } else { +      Swig_typemap_clear(method, pattern); +    } +    items = nextSibling(items); +  } +  return SWIG_OK; + +} + +/* ---------------------------------------------------------------------- + * Language::typemapcopyDirective() + * ---------------------------------------------------------------------- */ + +int Language::typemapcopyDirective(Node *n) { +  String *method = Getattr(n, "method"); +  Parm *pattern = Getattr(n, "pattern"); +  Node *items = firstChild(n); +  int nsrc = 0; +  nsrc = ParmList_len(pattern); +  while (items) { +    ParmList *npattern = Getattr(items, "pattern"); +    if (nsrc != ParmList_len(npattern)) { +      Swig_error(input_file, line_number, "Can't copy typemap. Number of types differ.\n"); +    } else { +      if (Swig_typemap_copy(method, pattern, npattern) < 0) { +	Swig_error(input_file, line_number, "Can't copy typemap (%s) %s = %s\n", method, ParmList_str(pattern), ParmList_str(npattern)); +      } +    } +    items = nextSibling(items); +  } +  return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::typesDirective() + * ---------------------------------------------------------------------- */ + +int Language::typesDirective(Node *n) { +  Parm *parms = Getattr(n, "parms"); +  String *convcode = Getattr(n, "convcode"); /* optional user supplied conversion code for custom casting */ +  while (parms) { +    SwigType *t = Getattr(parms, "type"); +    String *v = Getattr(parms, "value"); +    if (!v) { +      SwigType_remember(t); +    } else { +      if (SwigType_issimple(t)) { +	SwigType_inherit(t, v, 0, convcode); +      } +    } +    parms = nextSibling(parms); +  } +  return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::cDeclaration() + * ---------------------------------------------------------------------- */ + +int Language::cDeclaration(Node *n) { + +  String *name = Getattr(n, "name"); +  String *symname = Getattr(n, "sym:name"); +  SwigType *type = Getattr(n, "type"); +  SwigType *decl = Getattr(n, "decl"); +  String *storage = Getattr(n, "storage"); +  Node *over; +  File *f_header = 0; +  SwigType *ty, *fullty; + +  if (Getattr(n, "feature:onlychildren")) { +    if (GetFlag(n, "feature:ignore")) { +      return SWIG_NOWRAP; +    } else { +      // Found an unignored templated method that has an empty template instantiation (%template()) +      // Ignore it unless it has been %rename'd +      if (Strncmp(symname, "__dummy_", 8) == 0 && Cmp(storage, "typedef") != 0) { +	SetFlag(n, "feature:ignore"); +	Swig_warning(WARN_LANG_TEMPLATE_METHOD_IGNORE, input_file, line_number, +	    "%%template() contains no name. Template method ignored: %s\n", Swig_name_decl(n)); +	return SWIG_NOWRAP; +      } +    } +  } + +  /* discards nodes following the access control rules */ +  if (cplus_mode != PUBLIC || !is_public(n)) { +    /* except for friends, they are not affected by access control */ +    int isfriend = Cmp(storage, "friend") == 0; +    if (!isfriend) { +      /* Check what the director needs. If the method is pure virtual, it is always needed. +       * Also wrap non-virtual protected members if asked for (allprotected mode). */ +      if (!(directorsEnabled() && ((is_member_director(CurrentClass, n) && need_nonpublic_member(n)) || isNonVirtualProtectedAccess(n)))) { +          return SWIG_NOWRAP; +      } +      // Prevent wrapping protected overloaded director methods more than once - +      // This bit of code is only needed due to the cDeclaration call in classHandler() +      String *wrapname = NewStringf("nonpublic_%s%s", symname, Getattr(n, "sym:overname")); +      if (Getattr(CurrentClass, wrapname)) { +	Delete(wrapname); +	return SWIG_NOWRAP; +      } +      SetFlag(CurrentClass, wrapname); +      Delete(wrapname); +    } +  } + +  if (Cmp(storage, "typedef") == 0) { +    Swig_save("cDeclaration", n, "type", NIL); +    SwigType *t = Copy(type); +    if (t) { +      SwigType_push(t, decl); +      Setattr(n, "type", t); +      typedefHandler(n); +    } +    Swig_restore(n); +    return SWIG_OK; +  } + +  /* If in import mode, we proceed no further */ +  if (ImportMode) +    return SWIG_NOWRAP; + +  /* If we're in extend mode and there is code, replace the $descriptor macros */ +  if (Extend) { +    String *code = Getattr(n, "code"); +    if (code) { +      Setfile(code, Getfile(n)); +      Setline(code, Getline(n)); +      Swig_cparse_replace_descriptor(code); +    } +  } + +  /* Overloaded symbol check */ +  over = Swig_symbol_isoverloaded(n); +  if (!overloading) { +    if (over) +      over = first_nontemplate(over); +    if (over && (over != n)) { +      Swig_warning(WARN_LANG_OVERLOAD_DECL, input_file, line_number, "Overloaded declaration ignored.  %s\n", Swig_name_decl(n)); +      Swig_warning(WARN_LANG_OVERLOAD_DECL, Getfile(over), Getline(over), "Previous declaration is %s\n", Swig_name_decl(over)); +      return SWIG_NOWRAP; +    } +  } + +  if (!validIdentifier(symname)) { +    Swig_warning(WARN_LANG_IDENTIFIER, input_file, line_number, "Can't wrap '%s' unless renamed to a valid identifier.\n", SwigType_namestr(symname)); +    return SWIG_NOWRAP; +  } + +  ty = NewString(type); +  SwigType_push(ty, decl); +  fullty = SwigType_typedef_resolve_all(ty); +  if (SwigType_isfunction(fullty)) { +    if (!SwigType_isfunction(ty)) { +      Delete(ty); +      ty = fullty; +      fullty = 0; +      ParmList *parms = SwigType_function_parms(ty, n); +      Setattr(n, "parms", parms); +    } +    /* Transform the node into a 'function' node and emit */ +    if (!CurrentClass) { +      f_header = Swig_filebyname("header"); + +      if (AddExtern) { +	if (f_header) { +	  if (Swig_storage_isextern(n) || (ForceExtern && !storage)) { +	    /* we don't need the 'extern' part in the C/C++ declaration, +	       and it produces some problems when namespace and SUN +	       Studio is used. + +	       Printf(f_header,"extern %s", SwigType_str(ty,name)); + +	       In fact generating extern declarations is quite error prone and is +	       no longer the default. Getting it right seems impossible with namespaces +	       and default arguments and when a method is declared with the various Windows +	       calling conventions - SWIG doesn't understand Windows (non standard) calling +	       conventions in the first place, so can't regenerate them. +	     */ +	    String *str = SwigType_str(ty, name); +	    Printf(f_header, "%s", str); +	    Delete(str); +	    { +	      DOH *t = Getattr(n, "throws"); +	      if (t) { +		Printf(f_header, " throw("); +		while (t) { +		  Printf(f_header, "%s", Getattr(t, "type")); +		  t = nextSibling(t); +		  if (t) +		    Printf(f_header, ","); +		} +		Printf(f_header, ")"); +	      } +	    } +	    Printf(f_header, ";\n"); +	  } else if (Swig_storage_isexternc(n)) { +	    /* here 'extern "C"' is needed */ +	    String *str = SwigType_str(ty, name); +	    Printf(f_header, "extern \"C\" %s;\n", str); +	    Delete(str); +	  } +	} +      } +    } +    /* This needs to check qualifiers */ +    if (SwigType_isqualifier(ty)) { +      SwigType *qual = SwigType_pop(ty); +      Setattr(n, "qualifier", qual); +      Delete(qual); +    } +    Delete(SwigType_pop_function(ty)); +    DohIncref(type); +    Setattr(n, "type", ty); + +    functionHandler(n); + +    Setattr(n, "type", type); +    Delete(ty); +    Delete(type); +    return SWIG_OK; +  } else { +    /* Some kind of variable declaration */ +    String *declaration = Copy(decl); +    Delattr(n, "decl"); +    if (!CurrentClass) { +      if (Swig_storage_isextern(n) || ForceExtern) { +	if (AddExtern) { +	  f_header = Swig_filebyname("header"); +	  if (f_header) { +	    String *str = SwigType_str(ty, name); +	    Printf(f_header, "%s %s;\n", Getattr(n, "storage"), str); +	    Delete(str); +	  } +	} +      } +    } +    if (!SwigType_ismutable(ty)) { +      SetFlag(n, "feature:immutable"); +    } +    /* If an array and elements are const, then read-only */ +    if (SwigType_isarray(ty)) { +      SwigType *tya = SwigType_array_type(ty); +      if (SwigType_isconst(tya)) { +	SetFlag(n, "feature:immutable"); +      } +      Delete(tya); +    } +    DohIncref(type); +    Setattr(n, "type", ty); +    variableHandler(n); +    Setattr(n, "type", type); +    Setattr(n, "decl", declaration); +    Delete(ty); +    Delete(type); +    Delete(fullty); +    return SWIG_OK; +  } +} + +/* ---------------------------------------------------------------------- + * Language::functionHandler() + * ---------------------------------------------------------------------- */ + +int Language::functionHandler(Node *n) { +  String *storage = Getattr(n, "storage"); +  int isfriend = CurrentClass && Cmp(storage, "friend") == 0; +  int isstatic = CurrentClass && Swig_storage_isstatic(n) && !(SmartPointer && Getattr(n, "allocate:smartpointeraccess")); +  Parm *p = Getattr(n, "parms"); +  if (GetFlag(n, "feature:del")) { +    /* the method acts like a delete operator, ie, we need to disown the parameter */ +    if (CurrentClass && !isstatic && !isfriend) { +      SetFlag(n, "feature:self:disown"); +    } else { +      if (p) +	SetFlag(p, "wrap:disown"); +    } +  } +  if (!CurrentClass) { +    globalfunctionHandler(n); +  } else { +    if (isstatic) { +      staticmemberfunctionHandler(n); +    } else if (isfriend) { +      int oldInClass = InClass; +      InClass = 0; +      globalfunctionHandler(n); +      InClass = oldInClass; +    } else { +      // This is a member function, set a flag so the documentation type is correct +      SetFlag(n, "memberfunction"); +      Node *explicit_n = 0; +      if (directorsEnabled() && is_member_director(CurrentClass, n) && !extraDirectorProtectedCPPMethodsRequired()) { +	bool virtual_but_not_pure_virtual = (!(Cmp(storage, "virtual")) && (Cmp(Getattr(n, "value"), "0") != 0)); +	if (virtual_but_not_pure_virtual) { +	  // Add additional wrapper which makes an explicit call to the virtual method (ie not a virtual call) +	  explicit_n = Copy(n); +	  String *new_symname = Copy(Getattr(n, "sym:name")); +	  String *suffix = Getattr(parentNode(n), "sym:name"); +	  Printv(new_symname, "SwigExplicit", suffix, NIL); +	  Setattr(explicit_n, "sym:name", new_symname); +	  Delattr(explicit_n, "storage"); +	  Delattr(explicit_n, "override"); +	  Delattr(explicit_n, "hides"); +	  SetFlag(explicit_n, "explicitcall"); +	  Setattr(n, "explicitcallnode", explicit_n); +	} +      } + +      memberfunctionHandler(n); + +      if (explicit_n) { +	memberfunctionHandler(explicit_n); +	Delattr(explicit_n, "explicitcall"); +	Delete(explicit_n); +      } +    } +  } +  return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::globalfunctionHandler() + * ---------------------------------------------------------------------- */ + +int Language::globalfunctionHandler(Node *n) { + +  Swig_require("globalfunctionHandler", n, "name", "sym:name", "type", "?parms", NIL); + +  String *name = Getattr(n, "name"); +  String *symname = Getattr(n, "sym:name"); +  SwigType *type = Getattr(n, "type"); +  ParmList *parms = Getattr(n, "parms"); + +  /* Check for callback mode */ +  String *cb = GetFlagAttr(n, "feature:callback"); +  if (cb) { +    String *cbname = Getattr(n, "feature:callback:name"); +    if (!cbname) { +      cbname = NewStringf(cb, symname); +      Setattr(n, "feature:callback:name", cbname); +    } + +    callbackfunctionHandler(n); +    if (Cmp(cbname, symname) == 0) { +      Delete(cbname); +      Swig_restore(n); +      return SWIG_NOWRAP; +    } +    Delete(cbname); +  } +  Setattr(n, "parms", nonvoid_parms(parms)); + +  String *extendname = Getattr(n, "extendname"); +  String *call = Swig_cfunction_call(extendname ? extendname : name, parms); +  String *cres = Swig_cresult(type, Swig_cresult_name(), call); +  Setattr(n, "wrap:action", cres); +  Delete(cres); +  Delete(call); +  functionWrapper(n); + +  Swig_restore(n); +  return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::callbackfunctionHandler() + * ---------------------------------------------------------------------- */ + +int Language::callbackfunctionHandler(Node *n) { +  Swig_require("callbackfunctionHandler", n, "name", "*sym:name", "*type", "?value", NIL); +  String *type = Getattr(n, "type"); +  String *name = Getattr(n, "name"); +  String *parms = Getattr(n, "parms"); +  String *cbname = Getattr(n, "feature:callback:name"); +  String *calltype = NewStringf("(%s (*)(%s))(%s)", SwigType_str(type, 0), ParmList_str(parms), SwigType_namestr(name)); +  SwigType *cbty = Copy(type); +  SwigType_add_function(cbty, parms); +  SwigType_add_pointer(cbty); + +  Setattr(n, "sym:name", cbname); +  Setattr(n, "type", cbty); +  Setattr(n, "value", calltype); + +  Node *ns = symbolLookup(cbname); +  if (!ns) +    constantWrapper(n); + +  Delete(cbty); + +  Swig_restore(n); +  return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::memberfunctionHandler() + * ---------------------------------------------------------------------- */ + +int Language::memberfunctionHandler(Node *n) { + +  Swig_require("memberfunctionHandler", n, "*name", "*sym:name", "*type", "?parms", "?value", NIL); + +  String *storage = Getattr(n, "storage"); +  String *name = Getattr(n, "name"); +  String *symname = Getattr(n, "sym:name"); +  SwigType *type = Getattr(n, "type"); +  String *value = Getattr(n, "value"); +  ParmList *parms = Getattr(n, "parms"); +  String *cb = GetFlagAttr(n, "feature:callback"); + +  if (Cmp(storage, "virtual") == 0) { +    if (Cmp(value, "0") == 0) { +      IsVirtual = PURE_VIRTUAL; +    } else { +      IsVirtual = PLAIN_VIRTUAL; +    } +  } else { +    IsVirtual = 0; +  } +  if (cb) { +    Node *cbn = NewHash(); +    String *cbname = Getattr(n, "feature:callback:name"); +    if (!cbname) { +      cbname = NewStringf(cb, symname); +    } + +    SwigType *cbty = Copy(type); +    SwigType_add_function(cbty, parms); +    SwigType_add_memberpointer(cbty, ClassName); +    String *cbvalue = NewStringf("&%s::%s", ClassName, name); +    Setattr(cbn, "sym:name", cbname); +    Setattr(cbn, "type", cbty); +    Setattr(cbn, "value", cbvalue); +    Setattr(cbn, "name", name); +    Setfile(cbn, Getfile(n)); +    Setline(cbn, Getline(n)); + +    memberconstantHandler(cbn); +    Setattr(n, "feature:callback:name", Swig_name_member(NSpace, ClassPrefix, cbname)); + +    Delete(cb); +    Delete(cbn); +    Delete(cbvalue); +    Delete(cbty); +    Delete(cbname); +    if (Cmp(cbname, symname) == 0) { +      Swig_restore(n); +      return SWIG_NOWRAP; +    } +  } + +  String *fname = Swig_name_member(NSpace, ClassPrefix, symname); +  if (Extend && SmartPointer) { +    if (!Getattr(n, "extendsmartclassname")) { +      Setattr(n, "extendsmartclassname", Getattr(CurrentClass, "allocate:smartpointerpointeeclassname")); +    } +  } +  // Set up the type for the cast to this class for use when wrapping const director (virtual) methods. +  // Note: protected director methods or when allprotected mode turned on. +  String *director_type = 0; +  if (!is_public(n) && (is_member_director(CurrentClass, n) || GetFlag(n, "explicitcall") || isNonVirtualProtectedAccess(n))) { +    director_type = Copy(DirectorClassName); +    String *qualifier = Getattr(n, "qualifier"); +    if (qualifier) +      SwigType_push(director_type, qualifier); +    SwigType_add_pointer(director_type); +  } + +  int DirectorExtraCall = 0; +  if (directorsEnabled() && is_member_director(CurrentClass, n) && !SmartPointer) +    if (extraDirectorProtectedCPPMethodsRequired()) +      DirectorExtraCall = CWRAP_DIRECTOR_TWO_CALLS; + +  if (GetFlag(n, "explicitcall")) +    DirectorExtraCall = CWRAP_DIRECTOR_ONE_CALL; + +  int extendmember = GetFlag(n, "isextendmember") ? Extend : 0; +  int flags = Getattr(n, "template") ? extendmember | SmartPointer : Extend | SmartPointer | DirectorExtraCall; +  Swig_MethodToFunction(n, NSpace, ClassType, flags, director_type, is_member_director(CurrentClass, n)); +  Setattr(n, "sym:name", fname); +  /* Explicitly save low-level and high-level documentation names */ +  Setattr(n, "doc:low:name", fname); +  Setattr(n, "doc:high:name", symname); + +  functionWrapper(n); + +  Delete(director_type); +  Delete(fname); +  Swig_restore(n); +  return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::staticmemberfunctionHandler() + * ---------------------------------------------------------------------- */ + +int Language::staticmemberfunctionHandler(Node *n) { + +  Swig_require("staticmemberfunctionHandler", n, "*name", "*sym:name", "*type", NIL); +  Swig_save("staticmemberfunctionHandler", n, "storage", NIL); +  String *name = Getattr(n, "name"); +  String *symname = Getattr(n, "sym:name"); +  SwigType *type = Getattr(n, "type"); +  ParmList *parms = Getattr(n, "parms"); +  String *cb = GetFlagAttr(n, "feature:callback"); +  String *cname, *mrename; + +  if (!Extend) { +    Node *sb = Getattr(n, "cplus:staticbase"); +    String *sname = Getattr(sb, "name"); +    if (isNonVirtualProtectedAccess(n)) +      cname = NewStringf("%s::%s", DirectorClassName, name); +    else +      cname = NewStringf("%s::%s", sname, name); +  } else { +    String *mname = Swig_name_mangle(ClassName); +    cname = Swig_name_member(NSpace, mname, name); +    Delete(mname); +  } +  mrename = Swig_name_member(NSpace, ClassPrefix, symname); + +  if (Extend) { +    String *code = Getattr(n, "code"); +    String *defaultargs = Getattr(n, "defaultargs"); +    String *mangled = Swig_name_mangle(mrename); +    Delete(mrename); +    mrename = mangled; + +    if (code) { +      // See Swig_MethodToFunction() for the explanation of this code. +      if (Getattr(n, "sym:overloaded")) { +	Append(cname, Getattr(defaultargs ? defaultargs : n, "sym:overname")); +      } else if (UseWrapperSuffix) { +	Append(cname, "__SWIG"); +      } + +      if (!defaultargs) { +	/* Hmmm. An added static member.  We have to create a little wrapper for this */ +	String *mangled_cname = Swig_name_mangle(cname); +	Swig_add_extension_code(n, mangled_cname, parms, type, code, CPlusPlus, 0); +	Setattr(n, "extendname", mangled_cname); +	Delete(mangled_cname); +      } +    } +  } + +  Setattr(n, "name", cname); +  Setattr(n, "sym:name", mrename); +  /* Explicitly save low-level and high-level documentation names */ +  Setattr(n, "doc:low:name", mrename); +  Setattr(n, "doc:high:name", symname); + +  if (cb) { +    String *cbname = NewStringf(cb, symname); +    Setattr(n, "feature:callback:name", Swig_name_member(NSpace, ClassPrefix, cbname)); +    Setattr(n, "feature:callback:staticname", name); +  } +  Delattr(n, "storage"); + +  globalfunctionHandler(n); + +  Delete(cname); +  Delete(mrename); +  Swig_restore(n); +  return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::variableHandler() + * ---------------------------------------------------------------------- */ + +int Language::variableHandler(Node *n) { + +  /* If not a smart-pointer access or added method. We clear +     feature:except.   There is no way C++ or C would throw +     an exception merely for accessing a member data. + +     Caveat:  Some compilers seem to route attribute access through +     methods which can generate exceptions.  The feature:allowexcept +     allows this. Also, the feature:exceptvar can be used to match +     only variables. +   */ +  if (!(Extend | SmartPointer)) { +    if (!GetFlag(n, "feature:allowexcept")) { +      UnsetFlag(n, "feature:except"); +    } +    if (Getattr(n, "feature:exceptvar")) { +      Setattr(n, "feature:except", Getattr(n, "feature:exceptvar")); +    } +  } + +  if (!CurrentClass) { +    globalvariableHandler(n); +  } else { +    Swig_save("variableHandler", n, "feature:immutable", NIL); +    if (SmartPointer) { +      /* If a smart-pointer and it's a constant access, we have to set immutable */ +      if (!Getattr(CurrentClass, "allocate:smartpointermutable")) { +	SetFlag(n, "feature:immutable"); +      } +    } +    if (Swig_storage_isstatic(n) && !(SmartPointer && Getattr(n, "allocate:smartpointeraccess"))) { +      staticmembervariableHandler(n); +    } else { +      membervariableHandler(n); +    } +    Swig_restore(n); +  } +  return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::globalvariableHandler() + * ---------------------------------------------------------------------- */ + +int Language::globalvariableHandler(Node *n) { +  variableWrapper(n); +  return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::membervariableHandler() + * ---------------------------------------------------------------------- */ + +int Language::membervariableHandler(Node *n) { + +  Swig_require("membervariableHandler", n, "*name", "*sym:name", "*type", NIL); +  Swig_save("membervariableHandler", n, "parms", NIL); + +  String *name = Getattr(n, "name"); +  String *symname = Getattr(n, "sym:name"); +  SwigType *type = Getattr(n, "type"); + +  if (!AttributeFunctionGet) { +    String *mname = Swig_name_member(0, ClassPrefix, symname); +    String *mrename_get = Swig_name_get(NSpace, mname); +    String *mrename_set = Swig_name_set(NSpace, mname); +    Delete(mname); + +    /* Create a function to set the value of the variable */ + +    int assignable = is_assignable(n); + +    if (SmartPointer) { +      if (!Getattr(CurrentClass, "allocate:smartpointermutable")) {  +	assignable = 0; +      } +    } + +    if (assignable) { +      int make_set_wrapper = 1; +      String *tm = 0; +      String *target = 0; +      if (!Extend) { +	if (SmartPointer) { +	  if (Swig_storage_isstatic(n)) { +	    Node *sn = Getattr(n, "cplus:staticbase"); +	    String *base = Getattr(sn, "name"); +	    target = NewStringf("%s::%s", base, name); +	  } else { +	    String *pname = Swig_cparm_name(0, 0); +	    target = NewStringf("(*%s)->%s", pname, name); +	    Delete(pname); +	  } +	} else { +	  String *pname = isNonVirtualProtectedAccess(n) ? NewString("darg") : Swig_cparm_name(0, 0); +	  target = NewStringf("%s->%s", pname, name); +	  Delete(pname); +	} + +	// This is an input type typemap lookup and so it should not use Node n +	// otherwise qualification is done on the parameter name for the setter function +	Parm *nin = NewParm(type, name, n); +	tm = Swig_typemap_lookup("memberin", nin, target, 0); +	Delete(nin); +      } + +      int flags = Extend | SmartPointer | use_naturalvar_mode(n); +      if (isNonVirtualProtectedAccess(n)) +        flags = flags | CWRAP_ALL_PROTECTED_ACCESS; + +      Swig_MembersetToFunction(n, ClassType, flags); +      Setattr(n, "memberset", "1"); +      if (!Extend) { +	/* Check for a member in typemap here */ + +	if (!tm) { +	  if (SwigType_isarray(type)) { +	    Swig_warning(WARN_TYPEMAP_VARIN_UNDEF, input_file, line_number, "Unable to set variable of type %s.\n", SwigType_str(type, 0)); +	    make_set_wrapper = 0; +	  } +	} else { +	  String *pname0 = Swig_cparm_name(0, 0); +	  String *pname1 = Swig_cparm_name(0, 1); +	  Replace(tm, "$input", pname1, DOH_REPLACE_ANY); +	  Replace(tm, "$self", pname0, DOH_REPLACE_ANY); +	  Setattr(n, "wrap:action", tm); +	  Delete(tm); +	  Delete(pname0); +	  Delete(pname1); +	} +	Delete(target); +      } +      if (make_set_wrapper) { +	Setattr(n, "sym:name", mrename_set); +	functionWrapper(n); +      } else { +	SetFlag(n, "feature:immutable"); +      } +      /* Restore parameters */ +      Setattr(n, "type", type); +      Setattr(n, "name", name); +      Setattr(n, "sym:name", symname); +      Delattr(n, "memberset"); + +      /* Delete all attached typemaps and typemap attributes */ +      Iterator ki; +      for (ki = First(n); ki.key; ki = Next(ki)) { +	if (Strncmp(ki.key, "tmap:", 5) == 0) +	  Delattr(n, ki.key); +      } +    } +    /* Emit get function */ +    { +      int flags = Extend | SmartPointer | use_naturalvar_mode(n); +      if (isNonVirtualProtectedAccess(n)) +        flags = flags | CWRAP_ALL_PROTECTED_ACCESS; +      Swig_MembergetToFunction(n, ClassType, flags); +      Setattr(n, "sym:name", mrename_get); +      Setattr(n, "memberget", "1"); +      functionWrapper(n); +      Delattr(n, "memberget"); +    } +    Delete(mrename_get); +    Delete(mrename_set); + +  } else { + +    /* This code is used to support the attributefunction directive  +       where member variables are converted automagically to  +       accessor functions */ + +#if 0 +    Parm *p; +    String *gname; +    SwigType *vty; +    p = NewParm(type, 0, n); +    gname = NewStringf(AttributeFunctionGet, symname); +    if (!Extend) { +      ActionFunc = Copy(Swig_cmemberget_call(name, type)); +      cpp_member_func(Char(gname), Char(gname), type, 0); +      Delete(ActionFunc); +    } else { +      String *cname = Swig_name_get(NSpace, name); +      cpp_member_func(Char(cname), Char(gname), type, 0); +      Delete(cname); +    } +    Delete(gname); +    if (!GetFlag(n, "feature:immutable")) { +      gname = NewStringf(AttributeFunctionSet, symname); +      vty = NewString("void"); +      if (!Extend) { +	ActionFunc = Copy(Swig_cmemberset_call(name, type)); +	cpp_member_func(Char(gname), Char(gname), vty, p); +	Delete(ActionFunc); +      } else { +	String *cname = Swig_name_set(NSpace, name); +	cpp_member_func(Char(cname), Char(gname), vty, p); +	Delete(cname); +      } +      Delete(gname); +    } +    ActionFunc = 0; +#endif +  } +  Swig_restore(n); +  return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::staticmembervariableHandler() + * ---------------------------------------------------------------------- */ + +int Language::staticmembervariableHandler(Node *n) { +  Swig_require("staticmembervariableHandler", n, "*name", "*sym:name", "*type", "?value", NIL); +  String *value = Getattr(n, "value"); +  String *classname = !SmartPointer ? (isNonVirtualProtectedAccess(n) ? DirectorClassName : ClassName) : Getattr(CurrentClass, "allocate:smartpointerpointeeclassname"); + +  if (!value || !Getattr(n, "hasconsttype")) { +    String *name = Getattr(n, "name"); +    String *symname = Getattr(n, "sym:name"); +    String *cname, *mrename; + +    /* Create the variable name */ +    mrename = Swig_name_member(0, ClassPrefix, symname); +    cname = NewStringf("%s::%s", classname, name); + +    Setattr(n, "sym:name", mrename); +    Setattr(n, "name", cname); + +    /* Wrap as an ordinary global variable */ +    variableWrapper(n); + +    Delete(mrename); +    Delete(cname); +  } else { + +    /* This is a C++ static member declaration with an initializer and it's const. +       Certain C++ compilers optimize this out so that there is no linkage to a +       memory address.  Example: + +       class Foo { +       public: +         static const int x = 3; +       }; + +       Some discussion of this in section 9.4 of the C++ draft standard. + +       Also, we have to manage the case: + +       class Foo { +       public: +       %extend { +         static const int x = 3; +       } +       }; + +       in which there's no actual Foo::x variable to refer to. In this case, +       the best we can do is to wrap the given value verbatim. +     */ + + +    String *name = Getattr(n, "name"); +    String *cname = NewStringf("%s::%s", classname, name); +    if (Extend) { +      /* the variable is a synthesized one. +         There's nothing we can do; we just keep the given value */ +    } else { +      /* we refer to the value as Foo::x */ +      String *value = SwigType_namestr(cname); +      Setattr(n, "value", value); +    } + +    SwigType *t1 = SwigType_typedef_resolve_all(Getattr(n, "type")); +    SwigType *t2 = SwigType_strip_qualifiers(t1); +    Setattr(n, "type", t2); +    Delete(t1); +    Delete(t2); +    SetFlag(n, "wrappedasconstant"); +    memberconstantHandler(n); +    Delete(cname); +  } + +  Swig_restore(n); +  return SWIG_OK; +} + + +/* ---------------------------------------------------------------------- + * Language::externDeclaration() + * ---------------------------------------------------------------------- */ + +int Language::externDeclaration(Node *n) { +  return emit_children(n); +} + +/* ---------------------------------------------------------------------- + * Language::enumDeclaration() + * ---------------------------------------------------------------------- */ + +int Language::enumDeclaration(Node *n) { +  if (CurrentClass && (cplus_mode != PUBLIC)) +    return SWIG_NOWRAP; + +  String *oldNSpace = NSpace; +  NSpace = Getattr(n, "sym:nspace"); + +  String *oldEnumClassPrefix = EnumClassPrefix; +  if (GetFlag(n, "scopedenum")) { +    assert(Getattr(n, "sym:name")); +    assert(Getattr(n, "name")); +    EnumClassPrefix = ClassPrefix ? NewStringf("%s_", ClassPrefix) : NewString(""); +    Printv(EnumClassPrefix, Getattr(n, "sym:name"), NIL); +    EnumClassName = Copy(Getattr(n, "name")); +  } +  if (!ImportMode) { +    emit_children(n); +  } + +  if (GetFlag(n, "scopedenum")) { +    Delete(EnumClassName); +    EnumClassName = 0; +    Delete(EnumClassPrefix); +    EnumClassPrefix = oldEnumClassPrefix; +  } +  NSpace = oldNSpace; + +  return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::enumvalueDeclaration() + * ---------------------------------------------------------------------- */ + +int Language::enumvalueDeclaration(Node *n) { +  if (CurrentClass && (cplus_mode != PUBLIC)) +    return SWIG_NOWRAP; + +  Swig_require("enumvalueDeclaration", n, "*name", "*sym:name", "?value", NIL); +  String *value = Getattr(n, "value"); +  String *name = Getattr(n, "name"); +  String *tmpValue; + +  if (value) +    tmpValue = NewString(value); +  else +    tmpValue = NewString(name); +  Setattr(n, "value", tmpValue); + +  Node *parent = parentNode(n); +  if (GetFlag(parent, "scopedenum")) { +    String *symname = Swig_name_member(0, Getattr(parent, "sym:name"), Getattr(n, "sym:name")); +    Setattr(n, "sym:name", symname); +    Delete(symname); +  } + +  if (!CurrentClass || !cparse_cplusplus) { +    Setattr(n, "name", tmpValue);	/* for wrapping of enums in a namespace when emit_action is used */ +    constantWrapper(n); +  } else { +    memberconstantHandler(n); +  } + +  Delete(tmpValue); +  Swig_restore(n); +  return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::enumforwardDeclaration() + * ---------------------------------------------------------------------- */ + +int Language::enumforwardDeclaration(Node *n) { +  (void) n; +  if (GetFlag(n, "enumMissing")) +    enumDeclaration(n); // Generate an empty enum in target language +  return SWIG_OK; +} + +/* -----------------------------------------------------------------------------  + * Language::memberconstantHandler() + * ----------------------------------------------------------------------------- */ + +int Language::memberconstantHandler(Node *n) { + +  Swig_require("memberconstantHandler", n, "*name", "*sym:name", "value", NIL); + +  if (!GetFlag(n, "feature:allowexcept")) { +    UnsetFlag(n, "feature:except"); +  } +  if (Getattr(n, "feature:exceptvar")) { +    Setattr(n, "feature:except", Getattr(n, "feature:exceptvar")); +  } + +  String *enumvalue_symname = Getattr(n, "enumvalueDeclaration:sym:name"); // Only set if a strongly typed enum +  String *name = Getattr(n, "name"); +  String *symname = Getattr(n, "sym:name"); +  String *value = Getattr(n, "value"); + +  String *mrename = Swig_name_member(0, EnumClassPrefix, enumvalue_symname ? enumvalue_symname : symname); +  Setattr(n, "sym:name", mrename); + +  String *new_name = 0; +  if (Extend) +    new_name = Copy(value); +  else if (EnumClassName) +    new_name = NewStringf("%s::%s", isNonVirtualProtectedAccess(n) ? DirectorClassName : EnumClassName, name); +  else +    new_name = NewStringf("%s::%s", isNonVirtualProtectedAccess(n) ? DirectorClassName : ClassName, name); +  Setattr(n, "name", new_name); + +  constantWrapper(n); +  Delete(mrename); +  Delete(new_name); +  Swig_restore(n); +  return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::typedefHandler()  + * ---------------------------------------------------------------------- */ + +int Language::typedefHandler(Node *n) { +  /* since this is a recurring issue, we are going to remember the +     typedef pointer, if already it is not a pointer or reference, as +     in + +     typedef void NT; +     int func(NT *p);  + +     see director_basic.i for example. +   */ +  SwigType *name = Getattr(n, "name"); +  SwigType *decl = Getattr(n, "decl"); +  if (!SwigType_ispointer(decl) && !SwigType_isreference(decl)) { +    SwigType *pname = Copy(name); +    SwigType_add_pointer(pname); +    SwigType_remember(pname); +    Delete(pname); +  } +  return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::classDirectorMethod() + * ---------------------------------------------------------------------- */ + +int Language::classDirectorMethod(Node *n, Node *parent, String *super) { +  (void) n; +  (void) parent; +  (void) super; +  return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::classDirectorConstructor() + * ---------------------------------------------------------------------- */ + +int Language::classDirectorConstructor(Node *n) { +  (void) n; +  return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::classDirectorDefaultConstructor() + * ---------------------------------------------------------------------- */ + +int Language::classDirectorDefaultConstructor(Node *n) { +  (void) n; +  return SWIG_OK; +} + +static String *vtable_method_id(Node *n) { +  String *nodeType = Getattr(n, "nodeType"); +  int is_destructor = (Cmp(nodeType, "destructor") == 0); +  if (is_destructor) +    return 0; +  String *name = Getattr(n, "name"); +  String *decl = Getattr(n, "decl"); +  String *local_decl = SwigType_typedef_resolve_all(decl); +  String *tmp = SwigType_pop_function(local_decl); +  Delete(local_decl); +  local_decl = tmp; +  String *method_id = NewStringf("%s|%s", name, local_decl); +  Delete(local_decl); +  return method_id; +} + +/* ---------------------------------------------------------------------- + * Language::unrollOneVirtualMethod() + * ---------------------------------------------------------------------- */ + +void Language::unrollOneVirtualMethod(String *classname, Node *n, Node *parent, List *vm, int &virtual_destructor, int protectedbase) { +  if (!checkAttribute(n, "storage", "virtual")) +    return; +  if (GetFlag(n, "final")) +    return; + +  String *nodeType = Getattr(n, "nodeType"); + +  /* we need to add methods(cdecl) and destructor (to check for throw decl) */ +  int is_destructor = (Cmp(nodeType, "destructor") == 0); +  if ((Cmp(nodeType, "cdecl") == 0) || is_destructor) { +    String *decl = Getattr(n, "decl"); +    /* extra check for function type and proper access */ +    if (SwigType_isfunction(decl) && (((!protectedbase || dirprot_mode()) && is_public(n)) || need_nonpublic_member(n))) { +      String *name = Getattr(n, "name"); +      String *method_id = is_destructor ? NewStringf("~destructor") : vtable_method_id(n); +      /* Make sure that the new method overwrites the existing: */ +      int len = Len(vm); +      const int DO_NOT_REPLACE = -1; +      int replace = DO_NOT_REPLACE; +      for (int i = 0; i < len; i++) { +	Node *item = Getitem(vm, i); +	String *check_vmid = Getattr(item, "vmid"); + +	if (Strcmp(method_id, check_vmid) == 0) { +	  replace = i; +	  break; +	} +      } +      /* filling a new method item */ +      String *fqdname = NewStringf("%s::%s", classname, name); +      Hash *item = NewHash(); +      Setattr(item, "fqdname", fqdname); +      Node *m = Copy(n); + +      /* Store the complete return type - needed for non-simple return types (pointers, references etc.) */ +      SwigType *ty = NewString(Getattr(m, "type")); +      SwigType_push(ty, decl); +      if (SwigType_isqualifier(ty)) { +	Delete(SwigType_pop(ty)); +      } +      Delete(SwigType_pop_function(ty)); +      Setattr(m, "returntype", ty); + +      String *mname = NewStringf("%s::%s", Getattr(parent, "name"), name); +      /* apply the features of the original method found in the base class */ +      Swig_features_get(Swig_cparse_features(), 0, mname, Getattr(m, "decl"), m); +      Setattr(item, "methodNode", m); +      Setattr(item, "vmid", method_id); +      if (replace == DO_NOT_REPLACE) +	Append(vm, item); +      else +	Setitem(vm, replace, item); +      Setattr(n, "directorNode", m); + +      Delete(mname); +    } +    if (is_destructor) { +      virtual_destructor = 1; +    } +  } +} + +/* ---------------------------------------------------------------------- + * Language::unrollVirtualMethods() + * ---------------------------------------------------------------------- */ +int Language::unrollVirtualMethods(Node *n, Node *parent, List *vm, int &virtual_destructor, int protectedbase) { +  bool first_base = false; +  // recurse through all base classes to build the vtable +  List *bl = Getattr(n, "bases"); +  if (bl) { +    Iterator bi; +    for (bi = First(bl); bi.item; bi = Next(bi)) { +      if (first_base && !director_multiple_inheritance) +	break; +      unrollVirtualMethods(bi.item, parent, vm, virtual_destructor); +      first_base = true; +    } +  } + +  // recurse through all protected base classes to build the vtable, as needed +  bl = Getattr(n, "protectedbases"); +  if (bl) { +    Iterator bi; +    for (bi = First(bl); bi.item; bi = Next(bi)) { +      if (first_base && !director_multiple_inheritance) +	break; +      unrollVirtualMethods(bi.item, parent, vm, virtual_destructor, 1); +      first_base = true; +    } +  } + +  // find the methods that need directors +  String *classname = Getattr(n, "name"); +  for (Node *ni = firstChild(n); ni; ni = nextSibling(ni)) { +    /* we only need to check the virtual members */ +    if (Equal(nodeType(ni), "using")) { +      for (Node *nn = firstChild(ni); nn; nn = Getattr(nn, "sym:nextSibling")) { +	unrollOneVirtualMethod(classname, nn, parent, vm, virtual_destructor, protectedbase); +      } +    } +    unrollOneVirtualMethod(classname, ni, parent, vm, virtual_destructor, protectedbase); +  } + +  /* +     We delete all the nodirector methods. This prevents the +     generation of 'empty' director classes. + +     Done once we've collated all the virtual methods into vm. +   */ +  if (n == parent) { +    int len = Len(vm); +    for (int i = 0; i < len; i++) { +      Node *item = Getitem(vm, i); +      Node *m = Getattr(item, "methodNode"); +      /* retrieve the director features */ +      int mdir = GetFlag(m, "feature:director"); +      int mndir = GetFlag(m, "feature:nodirector"); +      /* 'nodirector' has precedence over 'director' */ +      int dir = (mdir || mndir) ? (mdir && !mndir) : 1; +      /* check if the method was found only in a base class */ +      Node *p = Getattr(m, "parentNode"); +      if (p != n) { +	Node *c = Copy(m); +	Setattr(c, "parentNode", n); +	int cdir = GetFlag(c, "feature:director"); +	int cndir = GetFlag(c, "feature:nodirector"); +	dir = (cdir || cndir) ? (cdir && !cndir) : dir; +	Delete(c); +      } +      if (dir) { +	/* be sure the 'nodirector' feature is disabled  */ +	if (mndir) +	  Delattr(m, "feature:nodirector"); +      } else { +	/* or just delete from the vm, since is not a director method */ +	Delitem(vm, i); +	len--; +	i--; +      } +    } +  } + +  return SWIG_OK; +} + + +/* ---------------------------------------------------------------------- + * Language::classDirectorDisown() + * ---------------------------------------------------------------------- */ + +int Language::classDirectorDisown(Node *n) { +  Node *disown = NewHash(); +  String *mrename; +  String *symname = Getattr(n, "sym:name"); +  mrename = Swig_name_disown(NSpace, symname); +  String *type = NewString(ClassType); +  String *name = NewString("self"); +  SwigType_add_pointer(type); +  Parm *p = NewParm(type, name, n); +  Delete(name); +  Delete(type); +  type = NewString("void"); +  String *action = NewString(""); +  Printv(action, "{\n", "Swig::Director *director = SWIG_DIRECTOR_CAST(arg1);\n", "if (director) director->swig_disown();\n", "}\n", NULL); +  Setfile(disown, Getfile(n)); +  Setline(disown, Getline(n)); +  Setattr(disown, "wrap:action", action); +  Setattr(disown, "name", mrename); +  Setattr(disown, "sym:name", mrename); +  Setattr(disown, "type", type); +  Setattr(disown, "parms", p); +  Delete(action); +  Delete(mrename); +  Delete(type); +  Delete(p); + +  functionWrapper(disown); +  Delete(disown); +  return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::classDirectorConstructors() + * ---------------------------------------------------------------------- */ + +int Language::classDirectorConstructors(Node *n) { +  Node *ni; +  String *nodeType; +  Node *parent = Swig_methodclass(n); +  int default_ctor = Getattr(parent, "allocate:default_constructor") ? 1 : 0; +  int protected_ctor = 0; +  int constructor = 0; + +  /* emit constructors */ +  for (ni = Getattr(n, "firstChild"); ni; ni = nextSibling(ni)) { +    nodeType = Getattr(ni, "nodeType"); +    if (Cmp(nodeType, "constructor") == 0) { +      if (GetFlag(ni, "feature:ignore")) +        continue; + +      Parm *parms = Getattr(ni, "parms"); +      if (is_public(ni)) { +	/* emit public constructor */ +	classDirectorConstructor(ni); +	constructor = 1; +	if (default_ctor) +	  default_ctor = !ParmList_numrequired(parms); +      } else { +	/* emit protected constructor if needed */ +	if (need_nonpublic_ctor(ni)) { +	  classDirectorConstructor(ni); +	  constructor = 1; +	  protected_ctor = 1; +	  if (default_ctor) +	    default_ctor = !ParmList_numrequired(parms); +	} +      } +    } +  } +  /* emit default constructor if needed */ +  if (!constructor) { +    if (!default_ctor) { +      /* we get here because the class has no public, protected or +         default constructor, therefore, the director class can't be +         created, ie, is kind of abstract. */ +      Swig_warning(WARN_LANG_DIRECTOR_ABSTRACT, Getfile(n), Getline(n), "Director class '%s' can't be constructed\n", SwigType_namestr(Getattr(n, "name"))); +      return SWIG_OK; +    } +    classDirectorDefaultConstructor(n); +    default_ctor = 1; +  } +  /* this is just to support old java behavior, ie, the default +     constructor is always emitted, even when protected, and not +     needed, since there is a public constructor already defined.   + +     (scottm) This code is needed here to make the director_abstract + +     test generate compilable code (Example2 in director_abstract.i). + +     (mmatus) This is very strange, since swig compiled with gcc3.2.3 +     doesn't need it here.... +   */ +  if (!default_ctor && !protected_ctor) { +    if (Getattr(parent, "allocate:default_base_constructor")) { +      classDirectorDefaultConstructor(n); +    } +  } + +  return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::classDirectorMethods() + * ---------------------------------------------------------------------- */ + +int Language::classDirectorMethods(Node *n) { +  Node *vtable = Getattr(n, "vtable"); + +  int len = Len(vtable); +  for (int i = 0; i < len; i++) { +    Node *item = Getitem(vtable, i); +    String *method = Getattr(item, "methodNode"); +    String *fqdname = Getattr(item, "fqdname"); +    if (GetFlag(method, "feature:nodirector") || GetFlag(method, "final")) +      continue; + +    String *wrn = Getattr(method, "feature:warnfilter"); +    if (wrn) +      Swig_warnfilter(wrn, 1); + +    String *type = Getattr(method, "nodeType"); +    if (!Cmp(type, "destructor")) { +      classDirectorDestructor(method); +    } else { +      Swig_require("classDirectorMethods", method, "*type", NIL); +      assert(Getattr(method, "returntype")); +      Setattr(method, "type", Getattr(method, "returntype")); +      if (classDirectorMethod(method, n, fqdname) == SWIG_OK) +	SetFlag(item, "director"); +      Swig_restore(method); +    } +    if (wrn) +      Swig_warnfilter(wrn, 0); +  } + +  return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::classDirectorInit() + * ---------------------------------------------------------------------- */ + +int Language::classDirectorInit(Node *n) { +  (void) n; +  return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::classDirectorDestructor() + * ---------------------------------------------------------------------- */ + +int Language::classDirectorDestructor(Node *n) { +  /*  +     Always emit the virtual destructor in the declaration and in the +     compilation unit.  Been explicit here can't make any damage, and +     can solve some nasty C++ compiler problems. +   */ +  File *f_directors = Swig_filebyname("director"); +  File *f_directors_h = Swig_filebyname("director_h"); +  if (Getattr(n, "throw")) { +    Printf(f_directors_h, "    virtual ~%s() throw();\n", DirectorClassName); +    Printf(f_directors, "%s::~%s() throw() {\n}\n\n", DirectorClassName, DirectorClassName); +  } else { +    Printf(f_directors_h, "    virtual ~%s();\n", DirectorClassName); +    Printf(f_directors, "%s::~%s() {\n}\n\n", DirectorClassName, DirectorClassName); +  } +  return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::classDirectorEnd() + * ---------------------------------------------------------------------- */ + +int Language::classDirectorEnd(Node *n) { +  (void) n; +  return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::classDirector() + * ---------------------------------------------------------------------- */ + +int Language::classDirector(Node *n) { +  Node *module = Getattr(n, "module"); +  String *classtype = Getattr(n, "classtype"); +  Hash *directormap = 0; +  if (module) { +    directormap = Getattr(module, "wrap:directormap"); +    if (directormap == 0) { +      directormap = NewHash(); +      Setattr(module, "wrap:directormap", directormap); +    } +  } +  List *vtable = NewList(); +  int virtual_destructor = 0; +  unrollVirtualMethods(n, n, vtable, virtual_destructor); + +  // Emit all the using base::member statements for non virtual members (allprotected mode) +  Node *ni; +  String *using_protected_members_code = NewString(""); +  for (ni = Getattr(n, "firstChild"); ni; ni = nextSibling(ni)) { +    Node *nodeType = Getattr(ni, "nodeType"); +    if (Cmp(nodeType, "destructor") == 0 && GetFlag(ni, "final")) { +      String *classtype = Getattr(n, "classtype"); +      SWIG_WARN_NODE_BEGIN(ni); +      Swig_warning(WARN_LANG_DIRECTOR_FINAL, input_file, line_number, "Destructor %s is final, %s cannot be a director class.\n", Swig_name_decl(ni), classtype); +      SWIG_WARN_NODE_END(ni); +      SetFlag(n, "feature:nodirector"); +      Delete(vtable); +      Delete(using_protected_members_code); +      return SWIG_OK; +    } +    bool cdeclaration = (Cmp(nodeType, "cdecl") == 0); +    if (cdeclaration && !GetFlag(ni, "feature:ignore")) { +      if (isNonVirtualProtectedAccess(ni)) { +        Node *overloaded = Getattr(ni, "sym:overloaded"); +        // emit the using base::member statement (but only once if the method is overloaded) +        if (!overloaded || (overloaded && (overloaded == ni))) +          Printf(using_protected_members_code, "    using %s::%s;\n", SwigType_namestr(ClassName), Getattr(ni, "name")); +      } +    } +  } + +  if (virtual_destructor || Len(vtable) > 0) { +    if (!virtual_destructor) { +      String *classtype = Getattr(n, "classtype"); +      Swig_warning(WARN_LANG_DIRECTOR_VDESTRUCT, input_file, line_number, "Director base class %s has no virtual destructor.\n", classtype); +    } + +    Setattr(n, "vtable", vtable); +    if (directormap != 0) { +      Setattr(directormap, classtype, n); +    } +    classDirectorInit(n); +    classDirectorConstructors(n); +    classDirectorMethods(n); + +    File *f_directors_h = Swig_filebyname("director_h"); +    Printv(f_directors_h, using_protected_members_code, NIL); + +    classDirectorEnd(n); +  } +  Delete(vtable); +  Delete(using_protected_members_code); +  return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::classDeclaration() + * ---------------------------------------------------------------------- */ + +static void addCopyConstructor(Node *n) { +  Node *cn = NewHash(); +  set_nodeType(cn, "constructor"); +  Setattr(cn, "access", "public"); +  Setfile(cn, Getfile(n)); +  Setline(cn, Getline(n)); + +  String *cname = Getattr(n, "name"); +  SwigType *type = Copy(cname); +  String *name = Swig_scopename_last(cname); +  String *cc = NewStringf("r.q(const).%s", type); +  String *decl = NewStringf("f(%s).", cc); +  String *oldname = Getattr(n, "sym:name"); + +  if (Getattr(n, "allocate:has_constructor")) { +    // to work properly with '%rename Class', we must look +    // for any other constructor in the class, which has not been +    // renamed, and use its name as oldname. +    Node *c; +    for (c = firstChild(n); c; c = nextSibling(c)) { +      const char *tag = Char(nodeType(c)); +      if (strcmp(tag, "constructor") == 0) { +	String *cname = Getattr(c, "name"); +	String *csname = Getattr(c, "sym:name"); +	String *clast = Swig_scopename_last(cname); +	if (Equal(csname, clast)) { +	  oldname = csname; +	  break; +	} +      } +    } +  } + +  String *symname = Swig_name_make(cn, cname, name, decl, oldname); +  if (Strcmp(symname, "$ignore") != 0) { +    Parm *p = NewParm(cc, "other", n); + +    Setattr(cn, "name", name); +    Setattr(cn, "sym:name", symname); +    SetFlag(cn, "feature:new"); +    Setattr(cn, "decl", decl); +    Setattr(cn, "parentNode", n); +    Setattr(cn, "parms", p); +    Setattr(cn, "copy_constructor", "1"); + +    Symtab *oldscope = Swig_symbol_setscope(Getattr(n, "symtab")); +    Node *on = Swig_symbol_add(symname, cn); +    Swig_features_get(Swig_cparse_features(), Swig_symbol_qualifiedscopename(0), name, decl, cn); +    Swig_symbol_setscope(oldscope); + +    if (on == cn) { +      Node *access = NewHash(); +      set_nodeType(access, "access"); +      Setattr(access, "kind", "public"); +      appendChild(n, access); +      appendChild(n, cn); +      Setattr(n, "has_copy_constructor", "1"); +      Setattr(n, "copy_constructor_decl", decl); +      Setattr(n, "allocate:copy_constructor", "1"); +      Delete(access); +    } +  } +  Delete(cn); +  Delete(name); +  Delete(decl); +  Delete(symname); +} + +static void addDefaultConstructor(Node *n) { +  Node *cn = NewHash(); +  set_nodeType(cn, "constructor"); +  Setattr(cn, "access", "public"); +  Setfile(cn, Getfile(n)); +  Setline(cn, Getline(n)); + +  String *cname = Getattr(n, "name"); +  String *name = Swig_scopename_last(cname); +  String *decl = NewString("f()."); +  String *oldname = Getattr(n, "sym:name"); +  String *symname = Swig_name_make(cn, cname, name, decl, oldname); +  if (Strcmp(symname, "$ignore") != 0) { +    Setattr(cn, "name", name); +    Setattr(cn, "sym:name", symname); +    SetFlag(cn, "feature:new"); +    Setattr(cn, "decl", decl); +    Setattr(cn, "parentNode", n); +    Setattr(cn, "default_constructor", "1"); +    Symtab *oldscope = Swig_symbol_setscope(Getattr(n, "symtab")); +    Node *on = Swig_symbol_add(symname, cn); +    Swig_features_get(Swig_cparse_features(), Swig_symbol_qualifiedscopename(0), name, decl, cn); +    Swig_symbol_setscope(oldscope); + +    if (on == cn) { +      Node *access = NewHash(); +      set_nodeType(access, "access"); +      Setattr(access, "kind", "public"); +      appendChild(n, access); +      appendChild(n, cn); +      Setattr(n, "has_default_constructor", "1"); +      Setattr(n, "allocate:default_constructor", "1"); +      Delete(access); +    } +  } +  Delete(cn); +  Delete(name); +  Delete(decl); +  Delete(symname); +} + +static void addDestructor(Node *n) { +  Node *cn = NewHash(); +  set_nodeType(cn, "destructor"); +  Setattr(cn, "access", "public"); +  Setfile(cn, Getfile(n)); +  Setline(cn, Getline(n)); + +  String *cname = Getattr(n, "name"); +  String *name = Swig_scopename_last(cname); +  Insert(name, 0, "~"); +  String *decl = NewString("f()."); +  String *symname = Swig_name_make(cn, cname, name, decl, 0); +  if (Strcmp(symname, "$ignore") != 0) { +    String *possible_nonstandard_symname = NewStringf("~%s", Getattr(n, "sym:name")); + +    Setattr(cn, "name", name); +    Setattr(cn, "sym:name", symname); +    Setattr(cn, "decl", "f()."); +    Setattr(cn, "parentNode", n); + +    Symtab *oldscope = Swig_symbol_setscope(Getattr(n, "symtab")); +    Node *nonstandard_destructor = Equal(possible_nonstandard_symname, symname) ? 0 : Swig_symbol_clookup(possible_nonstandard_symname, 0); +    Node *on = Swig_symbol_add(symname, cn); +    Swig_features_get(Swig_cparse_features(), Swig_symbol_qualifiedscopename(0), name, decl, cn); +    Swig_symbol_setscope(oldscope); + +    if (on == cn) { +      // SWIG accepts a non-standard named destructor in %extend that uses a typedef for the destructor name +      // For example: typedef struct X {} XX; %extend X { ~XX() {...} } +      // Don't add another destructor if a nonstandard one has been declared +      if (!nonstandard_destructor) { +	Node *access = NewHash(); +	set_nodeType(access, "access"); +	Setattr(access, "kind", "public"); +	appendChild(n, access); +	appendChild(n, cn); +	Setattr(n, "has_destructor", "1"); +	Setattr(n, "allocate:destructor", "1"); +	Delete(access); +      } +    } +    Delete(possible_nonstandard_symname); +  } +  Delete(cn); +  Delete(name); +  Delete(decl); +  Delete(symname); +} + +int Language::classDeclaration(Node *n) { +  String *ochildren = Getattr(n, "feature:onlychildren"); +  if (ochildren) { +    Setattr(n, "feature:emitonlychildren", ochildren); +    emit_children(n); +    Delattr(n, "feature:emitonlychildren"); +    SetFlag(n, "feature:ignore"); +    return SWIG_NOWRAP; +  } + +  // save class local variables for nested classes support +  int oldInClass = InClass; +  String *oldClassType = ClassType; +  String *oldClassPrefix = ClassPrefix; +  String *oldEnumClassPrefix = EnumClassPrefix; +  String *oldClassName = ClassName; +  String *oldDirectorClassName = DirectorClassName; +  String *oldNSpace = NSpace; +  Node *oldCurrentClass = CurrentClass; +  int dir = 0; + +  String *kind = Getattr(n, "kind"); +  String *name = Getattr(n, "name"); +  String *tdname = Getattr(n, "tdname"); +  String *unnamed = Getattr(n, "unnamed"); +  String *symname = Getattr(n, "sym:name"); + +  int strip = CPlusPlus ? 1 : unnamed && tdname; + +  if (cplus_mode != PUBLIC) +    return SWIG_NOWRAP; +  if (!name) { +    Swig_warning(WARN_LANG_CLASS_UNNAMED, input_file, line_number, "Can't generate wrappers for unnamed struct/class.\n"); +    return SWIG_NOWRAP; +  } + +  /* Check symbol name for template.   If not renamed. Issue a warning */ +  if (!validIdentifier(symname)) { +    Swig_warning(WARN_LANG_IDENTIFIER, input_file, line_number, "Can't wrap class %s unless renamed to a valid identifier.\n", SwigType_namestr(symname)); +    return SWIG_NOWRAP; +  } +  AccessMode oldAccessMode = cplus_mode; +  Node *outerClass = Getattr(n, "nested:outer"); +  if (outerClass && oldAccessMode != PUBLIC) +    return SWIG_NOWRAP; +  ClassName = Copy(name); +  ClassPrefix = Copy(symname); +  if (Cmp(kind, "class") == 0) { +    cplus_mode = PRIVATE; +  } else { +    cplus_mode = PUBLIC; +  } +  for (; outerClass; outerClass = Getattr(outerClass, "nested:outer")) { +    Push(ClassPrefix, "_"); +    Push(ClassPrefix, Getattr(outerClass, "sym:name")); +  } +  EnumClassPrefix = Copy(ClassPrefix); +  if (strip) { +    ClassType = Copy(name); +  } else { +    ClassType = NewStringf("%s %s", kind, name); +  } +  Setattr(n, "classtypeobj", Copy(ClassType)); +  Setattr(n, "classtype", SwigType_namestr(ClassType)); + +  InClass = 1; +  CurrentClass = n; +  NSpace = Getattr(n, "sym:nspace"); +  int oldAbstract = Abstract; + +  /* Call classHandler() here */ +  if (!ImportMode) { +    if (directorsEnabled()) { +      int ndir = GetFlag(n, "feature:director"); +      int nndir = GetFlag(n, "feature:nodirector"); +      /* 'nodirector' has precedence over 'director' */ +      dir = (ndir || nndir) ? (ndir && !nndir) : 0; +    } +    int abstract = !dir && abstractClassTest(n); +    int odefault = (GenerateDefault && !GetFlag(n, "feature:nodefault")); + +    /* default constructor */ +    if (!abstract && !GetFlag(n, "feature:nodefaultctor") && odefault) { +      if (!Getattr(n, "has_constructor") && !Getattr(n, "allocate:has_constructor") && (Getattr(n, "allocate:default_constructor"))) { +	addDefaultConstructor(n); +      } +    } +    /* copy constructor */ +    if (CPlusPlus && !abstract && GetFlag(n, "feature:copyctor")) { +      if (!Getattr(n, "has_copy_constructor") && !Getattr(n, "allocate:has_copy_constructor") +	  && (Getattr(n, "allocate:copy_constructor")) +	  && (!GetFlag(n, "feature:ignore"))) { +	addCopyConstructor(n); +      } +    } +    /* default destructor */ +    if (!GetFlag(n, "feature:nodefaultdtor") && odefault) { +      if (!Getattr(n, "has_destructor") && (!Getattr(n, "allocate:has_destructor")) +	  && (Getattr(n, "allocate:default_destructor")) +	  && (!GetFlag(n, "feature:ignore"))) { +	addDestructor(n); +      } +    } + +    if (dir) { +      DirectorClassName = directorClassName(n); +      classDirector(n); +    } +    /* check for abstract after resolving directors */ + +    Abstract = abstractClassTest(n); +    classHandler(n); +  } else { +    Abstract = abstractClassTest(n); +    Language::classHandler(n); +  } + +  Abstract = oldAbstract; +  cplus_mode = oldAccessMode; +  NSpace = oldNSpace; +  InClass = oldInClass; +  CurrentClass = oldCurrentClass; +  Delete(ClassType); +  ClassType = oldClassType; +  Delete(EnumClassPrefix); +  EnumClassPrefix = oldEnumClassPrefix; +  Delete(ClassPrefix); +  ClassPrefix = oldClassPrefix; +  Delete(ClassName); +  ClassName = oldClassName; +  if (dir) { +    Delete(DirectorClassName); +  } +  DirectorClassName = oldDirectorClassName; +  return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::classHandler() + * ---------------------------------------------------------------------- */ + +int Language::classHandler(Node *n) { +  save_value<int> oldExtend(Extend); +  if (Getattr(n, "template")) +    Extend = 0; +  bool hasDirector = Swig_directorclass(n) ? true : false; + +  /* Emit all of the class members */ +  emit_children(n); + +  /* Look for smart pointer handling */ +  if (Getattr(n, "allocate:smartpointer")) { +    List *methods = Getattr(n, "allocate:smartpointer"); +    cplus_mode = PUBLIC; +    SmartPointer = CWRAP_SMART_POINTER; +    if (Getattr(n, "allocate:smartpointerconst") && Getattr(n, "allocate:smartpointermutable")) { +      SmartPointer |= CWRAP_SMART_POINTER_OVERLOAD; +    } +    Iterator c; +    for (c = First(methods); c.item; c = Next(c)) { +      emit_one(c.item); +    } +    SmartPointer = 0; +  } + +  cplus_mode = PUBLIC; + +  /* emit director disown method */ +  if (hasDirector) { +    classDirectorDisown(n); + +    /* Emit additional protected virtual methods - only needed if the language module +     * codes logic in the C++ layer instead of the director proxy class method - primarily +     * to catch public use of protected methods by the scripting languages. */ +    if (dirprot_mode() && extraDirectorProtectedCPPMethodsRequired()) { +      Node *vtable = Getattr(n, "vtable"); +      String *symname = Getattr(n, "sym:name"); +      save_value<AccessMode> old_mode(cplus_mode); +      cplus_mode = PROTECTED; +      int len = Len(vtable); +      for (int i = 0; i < len; i++) { +	Node *item = Getitem(vtable, i); +	Node *method = Getattr(item, "methodNode"); +	SwigType *type = Getattr(method, "nodeType"); +	if (Strcmp(type, "cdecl") != 0) +	  continue; +	if (GetFlag(method, "feature:ignore")) +	  continue; +	String *methodname = Getattr(method, "sym:name"); +	String *wrapname = NewStringf("%s_%s", symname, methodname); +	if (!symbolLookup(wrapname, "") && (!is_public(method))) { +	  Node *m = Copy(method); +	  Setattr(m, "director", "1"); +	  Setattr(m, "parentNode", n); +	  /* +	   * There is a bug that needs fixing still...  +	   * This area of code is creating methods which have not been overridden in a derived class (director methods that are protected in the base) +	   * If the method is overloaded, then Swig_overload_dispatch() incorrectly generates a call to the base wrapper, _wrap_xxx method +	   * See director_protected_overloaded.i - Possibly sym:overname needs correcting here. +	  Printf(stdout, "new method: %s::%s(%s)\n", Getattr(parentNode(m), "name"), Getattr(m, "name"), ParmList_str_defaultargs(Getattr(m, "parms"))); +	  */ +	  cDeclaration(m); +	  Delete(m); +	} +	Delete(wrapname); +      } +    } +  } + +  return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::classforwardDeclaration() + * ---------------------------------------------------------------------- */ + +int Language::classforwardDeclaration(Node *n) { +  (void) n; +  return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::constructorDeclaration() + * ---------------------------------------------------------------------- */ + +int Language::constructorDeclaration(Node *n) { +  String *name = Getattr(n, "name"); +  String *symname = Getattr(n, "sym:name"); + +  if (!symname) +    return SWIG_NOWRAP; +  if (!CurrentClass) +    return SWIG_NOWRAP; +  if (ImportMode) +    return SWIG_NOWRAP; + +  if (Extend) { +    /* extend default constructor can be safely ignored if there is already one */ +    int num_required = ParmList_numrequired(Getattr(n, "parms")); +    if ((num_required == 0) && Getattr(CurrentClass, "has_default_constructor")) { +      return SWIG_NOWRAP; +    } +    if ((num_required == 1) && Getattr(CurrentClass, "has_copy_constructor")) { +      String *ccdecl = Getattr(CurrentClass, "copy_constructor_decl"); +      if (ccdecl && (Strcmp(ccdecl, Getattr(n, "decl")) == 0)) { +	return SWIG_NOWRAP; +      } +    } +  } + +  /* clean protected overloaded constructors, in case they are not needed anymore */ +  Node *over = Swig_symbol_isoverloaded(n); +  if (over && !Getattr(CurrentClass, "sym:cleanconstructor")) { +    int dirclass = Swig_directorclass(CurrentClass); +    Node *nn = over; +    while (nn) { +      if (!is_public(nn)) { +	if (!dirclass || !need_nonpublic_ctor(nn)) { +	  SetFlag(nn, "feature:ignore"); +	} +      } +      nn = Getattr(nn, "sym:nextSibling"); +    } +    clean_overloaded(over); +    Setattr(CurrentClass, "sym:cleanconstructor", "1"); +  } + +  if ((cplus_mode != PUBLIC)) { +    /* check only for director classes */ +    if (!Swig_directorclass(CurrentClass) || !need_nonpublic_ctor(n)) +      return SWIG_NOWRAP; +  } + +  /* Name adjustment for %name */ +  Swig_save("constructorDeclaration", n, "sym:name", NIL); + +  { +    String *base = Swig_scopename_last(name); +    if ((Strcmp(base, symname) == 0) && (Strcmp(symname, ClassPrefix) != 0)) { +      Setattr(n, "sym:name", ClassPrefix); +    } +    Delete(base); +  } + +  /* Only create a constructor if the class is not abstract */ +  if (!Abstract) { +    Node *over; +    over = Swig_symbol_isoverloaded(n); +    if (over) +      over = first_nontemplate(over); +    if ((over) && (!overloading)) { +      /* If the symbol is overloaded.  We check to see if it is a copy constructor.  If so,  +         we invoke copyconstructorHandler() as a special case. */ +      if (Getattr(n, "copy_constructor") && (!Getattr(CurrentClass, "has_copy_constructor"))) { +	copyconstructorHandler(n); +	Setattr(CurrentClass, "has_copy_constructor", "1"); +      } else { +	if (Getattr(over, "copy_constructor")) +	  over = Getattr(over, "sym:nextSibling"); +	if (over != n) { +	  Swig_warning(WARN_LANG_OVERLOAD_CONSTRUCT, input_file, line_number, +		       "Overloaded constructor ignored.  %s\n", Swig_name_decl(n)); +	  Swig_warning(WARN_LANG_OVERLOAD_CONSTRUCT, Getfile(over), Getline(over), +		       "Previous declaration is %s\n", Swig_name_decl(over)); +	} else { +	  constructorHandler(n); +	} +      } +    } else { +      String *expected_name = ClassName; +      String *scope = Swig_scopename_check(ClassName) ? Swig_scopename_prefix(ClassName) : 0; +      String *actual_name = scope ? NewStringf("%s::%s", scope, name) : NewString(name); +      Delete(scope); +      if (!Equal(actual_name, expected_name) && !SwigType_istemplate(expected_name) && !SwigType_istemplate(actual_name)) { +	// Checking templates is skipped but they ought to be checked... they are just somewhat more tricky to check correctly +	bool illegal_name = true; +	if (Extend) { +	  // Check for typedef names used as a constructor name in %extend. This is deprecated except for anonymous +	  // typedef structs which have had their symbol names adjusted to the typedef name in the parser. +	  SwigType *name_resolved = SwigType_typedef_resolve_all(actual_name); +	  SwigType *expected_name_resolved = SwigType_typedef_resolve_all(expected_name); + +	  if (!CPlusPlus) { +	    if (Strncmp(name_resolved, "struct ", 7) == 0) +	      Replace(name_resolved, "struct ", "", DOH_REPLACE_FIRST); +	    else if (Strncmp(name_resolved, "union ", 6) == 0) +	      Replace(name_resolved, "union ", "", DOH_REPLACE_FIRST); +	  } + +	  illegal_name = !Equal(name_resolved, expected_name_resolved); +	  if (!illegal_name) +	    Swig_warning(WARN_LANG_EXTEND_CONSTRUCTOR, input_file, line_number, "Use of an illegal constructor name '%s' in %%extend is deprecated, the constructor name should be '%s'.\n",  +		SwigType_str(Swig_scopename_last(actual_name), 0), SwigType_str(Swig_scopename_last(expected_name), 0)); +	  Delete(name_resolved); +	  Delete(expected_name_resolved); +	} +	if (illegal_name) { +	  Swig_warning(WARN_LANG_RETURN_TYPE, input_file, line_number, "Function %s must have a return type. Ignored.\n", Swig_name_decl(n)); +	  Swig_restore(n); +	  return SWIG_NOWRAP; +	} +      } +      constructorHandler(n); +    } +  } +  Setattr(CurrentClass, "has_constructor", "1"); + +  Swig_restore(n); +  return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * get_director_ctor_code() + * ---------------------------------------------------------------------- */ + +static String *get_director_ctor_code(Node *n, String *director_ctor_code, String *director_prot_ctor_code, List *&abstracts) { +  String *director_ctor = director_ctor_code; +  int use_director = Swig_directorclass(n); +  if (use_director) { +    Node *pn = Swig_methodclass(n); +    abstracts = Getattr(pn, "abstracts"); +    if (director_prot_ctor_code) { +      int is_notabstract = GetFlag(pn, "feature:notabstract"); +      int is_abstract = abstracts && !is_notabstract; +      if (is_protected(n) || is_abstract) { +	director_ctor = director_prot_ctor_code; +	abstracts = Copy(abstracts); +	Delattr(pn, "abstracts"); +      } else { +	if (is_notabstract) { +	  abstracts = Copy(abstracts); +	  Delattr(pn, "abstracts"); +	} else { +	  abstracts = 0; +	} +      } +    } +  } +  return director_ctor; +} + + +/* ---------------------------------------------------------------------- + * Language::constructorHandler() + * ---------------------------------------------------------------------- */ + +int Language::constructorHandler(Node *n) { +  Swig_require("constructorHandler", n, "?name", "*sym:name", "?type", "?parms", NIL); +  String *symname = Getattr(n, "sym:name"); +  String *mrename = Swig_name_construct(NSpace, symname); +  String *nodeType = Getattr(n, "nodeType"); +  int constructor = (!Cmp(nodeType, "constructor")); +  List *abstracts = 0; +  String *director_ctor = get_director_ctor_code(n, director_ctor_code, +						 director_prot_ctor_code, +						 abstracts); +  if (!constructor) { +    /* if not originally a constructor, still handle it as one */ +    Setattr(n, "handled_as_constructor", "1"); +  } + +  int extendmember = GetFlag(n, "isextendmember") ? Extend : 0; +  int flags = Getattr(n, "template") ? extendmember : Extend; +  Swig_ConstructorToFunction(n, NSpace, ClassType, none_comparison, director_ctor, CPlusPlus, flags, DirectorClassName); +  Setattr(n, "sym:name", mrename); +  functionWrapper(n); +  Delete(mrename); +  Swig_restore(n); +  if (abstracts) +    Setattr(Swig_methodclass(n), "abstracts", abstracts); +  return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::copyconstructorHandler() + * ---------------------------------------------------------------------- */ + +int Language::copyconstructorHandler(Node *n) { +  Swig_require("copyconstructorHandler", n, "?name", "*sym:name", "?type", "?parms", NIL); +  String *symname = Getattr(n, "sym:name"); +  String *mrename = Swig_name_copyconstructor(NSpace, symname); +  List *abstracts = 0; +  String *director_ctor = get_director_ctor_code(n, director_ctor_code, +						 director_prot_ctor_code, +						 abstracts); +  Swig_ConstructorToFunction(n, NSpace, ClassType, none_comparison, director_ctor, CPlusPlus, Getattr(n, "template") ? 0 : Extend, DirectorClassName); +  Setattr(n, "sym:name", mrename); +  functionWrapper(n); +  Delete(mrename); +  Swig_restore(n); +  if (abstracts) +    Setattr(Swig_methodclass(n), "abstracts", abstracts); +  return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::destructorDeclaration() + * ---------------------------------------------------------------------- */ + +int Language::destructorDeclaration(Node *n) { + +  if (!CurrentClass) +    return SWIG_NOWRAP; +  if (cplus_mode != PUBLIC && !Getattr(CurrentClass, "feature:unref")) +    return SWIG_NOWRAP; +  if (ImportMode) +    return SWIG_NOWRAP; + +  Swig_save("destructorDeclaration", n, "name", "sym:name", NIL); + +  char *c = GetChar(n, "sym:name"); +  if (c && (*c == '~')) { +    Setattr(n, "sym:name", c + 1); +  } + +  String *name = Getattr(n, "name"); +  String *symname = Getattr(n, "sym:name"); + +  if ((Strcmp(name, symname) == 0) || (Strcmp(symname, ClassPrefix) != 0)) { +    Setattr(n, "sym:name", ClassPrefix); +  } + +  String *expected_name = ClassName; +  String *scope = Swig_scopename_check(ClassName) ? Swig_scopename_prefix(ClassName) : 0; +  String *actual_name = scope ? NewStringf("%s::%s", scope, name) : NewString(name); +  Delete(scope); +  Replace(actual_name, "~", "", DOH_REPLACE_FIRST); +  if (!Equal(actual_name, expected_name) && !(Getattr(n, "template"))) { +    bool illegal_name = true; +    if (Extend) { +      // Check for typedef names used as a destructor name in %extend. This is deprecated except for anonymous +      // typedef structs which have had their symbol names adjusted to the typedef name in the parser. +      SwigType *name_resolved = SwigType_typedef_resolve_all(actual_name); +      SwigType *expected_name_resolved = SwigType_typedef_resolve_all(expected_name); + +      if (!CPlusPlus) { +	if (Strncmp(name_resolved, "struct ", 7) == 0) +	  Replace(name_resolved, "struct ", "", DOH_REPLACE_FIRST); +	else if (Strncmp(name_resolved, "union ", 6) == 0) +	  Replace(name_resolved, "union ", "", DOH_REPLACE_FIRST); +      } + +      illegal_name = !Equal(name_resolved, expected_name_resolved); +      if (!illegal_name) +	Swig_warning(WARN_LANG_EXTEND_DESTRUCTOR, input_file, line_number, "Use of an illegal destructor name '%s' in %%extend is deprecated, the destructor name should be '%s'.\n",  +	    SwigType_str(Swig_scopename_last(actual_name), 0), SwigType_str(Swig_scopename_last(expected_name), 0)); +      Delete(name_resolved); +      Delete(expected_name_resolved); +    } + +    if (illegal_name) { +      Swig_warning(WARN_LANG_ILLEGAL_DESTRUCTOR, input_file, line_number, "Illegal destructor name %s. Ignored.\n", Swig_name_decl(n)); +      Swig_restore(n); +      return SWIG_NOWRAP; +    } +  } +  destructorHandler(n); + +  Setattr(CurrentClass, "has_destructor", "1"); +  Swig_restore(n); +  return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::destructorHandler() + * ---------------------------------------------------------------------- */ + +int Language::destructorHandler(Node *n) { +  Swig_require("destructorHandler", n, "?name", "*sym:name", NIL); +  Swig_save("destructorHandler", n, "type", "parms", NIL); + +  String *symname = Getattr(n, "sym:name"); +  String *mrename; +  char *csymname = Char(symname); +  if (*csymname == '~') +    csymname += 1; + +  mrename = Swig_name_destroy(NSpace, csymname); + +  Swig_DestructorToFunction(n, NSpace, ClassType, CPlusPlus, Extend); +  Setattr(n, "sym:name", mrename); +  functionWrapper(n); +  Delete(mrename); +  Swig_restore(n); +  return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::accessDeclaration() + * ---------------------------------------------------------------------- */ + +int Language::accessDeclaration(Node *n) { +  String *kind = Getattr(n, "kind"); +  if (Cmp(kind, "public") == 0) { +    cplus_mode = PUBLIC; +  } else if (Cmp(kind, "private") == 0) { +    cplus_mode = PRIVATE; +  } else if (Cmp(kind, "protected") == 0) { +    cplus_mode = PROTECTED; +  } +  return SWIG_OK; +} + +/* ----------------------------------------------------------------------------- + * Language::namespaceDeclaration() + * ----------------------------------------------------------------------------- */ + +int Language::namespaceDeclaration(Node *n) { +  if (Getattr(n, "alias")) +    return SWIG_OK; +  if (Getattr(n, "unnamed")) +    return SWIG_OK; +  emit_children(n); +  return SWIG_OK; +} + +int Language::validIdentifier(String *s) { +  char *c = Char(s); +  while (*c) { +    if (!(isalnum(*c) || (*c == '_'))) +      return 0; +    c++; +  } +  return 1; +} + +/* ----------------------------------------------------------------------------- + * Language::usingDeclaration() + * ----------------------------------------------------------------------------- */ + +int Language::usingDeclaration(Node *n) { +  if ((cplus_mode == PUBLIC) || (!is_public(n) && dirprot_mode())) { +    Node *np = Copy(n); +    Node *c; +    for (c = firstChild(np); c; c = nextSibling(c)) { +      /* it seems for some cases this is needed, like A* A::boo() */ +      if (CurrentClass) +	Setattr(c, "parentNode", CurrentClass); +      emit_one(c); +    } +    Delete(np); +  } +  return SWIG_OK; +} + +/* Stubs. Language modules need to implement these */ + +/* ---------------------------------------------------------------------- + * Language::constantWrapper() + * ---------------------------------------------------------------------- */ + +int Language::constantWrapper(Node *n) { +  String *name = Getattr(n, "sym:name"); +  SwigType *type = Getattr(n, "type"); +  String *value = Getattr(n, "value"); +  String *str = SwigType_str(type, name); +  Printf(stdout, "constantWrapper   : %s = %s\n", str, value); +  Delete(str); +  return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::variableWrapper() + * ---------------------------------------------------------------------- */ + +int Language::variableWrapper(Node *n) { +  Swig_require("variableWrapper", n, "*name", "*sym:name", "*type", "?parms", "?varset", "?varget", NIL); +  String *symname = Getattr(n, "sym:name"); +  SwigType *type = Getattr(n, "type"); +  String *name = Getattr(n, "name"); + +  Delattr(n,"varset"); +  Delattr(n,"varget"); + +  String *newsymname = 0; +  if (!CurrentClass && EnumClassPrefix) { +    newsymname = Swig_name_member(0, EnumClassPrefix, symname); +    symname = newsymname; +  } + +  /* If no way to set variables.  We simply create functions */ +  int assignable = is_assignable(n); +  int flags = use_naturalvar_mode(n); +  if (!GetFlag(n, "wrappedasconstant")) +    flags = flags | Extend; + +  if (assignable) { +    int make_set_wrapper = 1; +    String *tm = Swig_typemap_lookup("globalin", n, name, 0); + +    Swig_VarsetToFunction(n, flags); +    String *sname = Swig_name_set(NSpace, symname); +    Setattr(n, "sym:name", sname); +    Delete(sname); + +    if (!tm) { +      if (SwigType_isarray(type)) { +	Swig_warning(WARN_TYPEMAP_VARIN_UNDEF, input_file, line_number, "Unable to set variable of type %s.\n", SwigType_str(type, 0)); +	make_set_wrapper = 0; +      } +    } else { +      String *pname0 = Swig_cparm_name(0, 0); +      Replace(tm, "$input", pname0, DOH_REPLACE_ANY); +      Setattr(n, "wrap:action", tm); +      Delete(tm); +      Delete(pname0); +    } +    if (make_set_wrapper) { +      Setattr(n, "varset", "1"); +      functionWrapper(n); +    } else { +      SetFlag(n, "feature:immutable"); +    } +    /* Restore parameters */ +    Setattr(n, "sym:name", symname); +    Setattr(n, "type", type); +    Setattr(n, "name", name); +    Delattr(n, "varset"); + +    /* Delete all attached typemaps and typemap attributes */ +    Iterator ki; +    for (ki = First(n); ki.key; ki = Next(ki)) { +      if (Strncmp(ki.key, "tmap:", 5) == 0) +	Delattr(n, ki.key); +    } +  } + +  Swig_VargetToFunction(n, flags); +  String *gname = Swig_name_get(NSpace, symname); +  Setattr(n, "sym:name", gname); +  Delete(gname); +  Setattr(n, "varget", "1"); +  functionWrapper(n); +  Delattr(n, "varget"); +  Swig_restore(n); +  Delete(newsymname); +  return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::functionWrapper() + * ---------------------------------------------------------------------- */ + +int Language::functionWrapper(Node *n) { +  String *name = Getattr(n, "sym:name"); +  SwigType *type = Getattr(n, "type"); +  ParmList *parms = Getattr(n, "parms"); + +  Printf(stdout, "functionWrapper   : %s\n", SwigType_str(type, NewStringf("%s(%s)", name, ParmList_str_defaultargs(parms)))); +  Printf(stdout, "           action : %s\n", Getattr(n, "wrap:action")); +  return SWIG_OK; +} + +/* ----------------------------------------------------------------------------- + * Language::nativeWrapper() + * ----------------------------------------------------------------------------- */ + +int Language::nativeWrapper(Node *n) { +  (void) n; +  return SWIG_OK; +} + +void Language::main(int argc, char *argv[]) { +  (void) argc; +  (void) argv; +} + +/* ----------------------------------------------------------------------------- + * Language::addSymbol() + * + * Adds a symbol entry into the target language symbol tables. + * Returns 1 if the symbol is added successfully. + * Prints an error message and returns 0 if a conflict occurs. + * The scope is optional for target languages and if supplied must be a fully + * qualified scope and the symbol s must not contain any scope qualifiers. + * ----------------------------------------------------------------------------- */ + +int Language::addSymbol(const String *s, const Node *n, const_String_or_char_ptr scope) { +  //Printf( stdout, "addSymbol: %s %s\n", s, scope ); +  Hash *symbols = Getattr(symtabs, scope ? scope : ""); +  if (!symbols) { +    symbols = symbolAddScope(scope); +  } else { +    Node *c = Getattr(symbols, s); +    if (c && (c != n)) { +      if (scope && Len(scope) > 0) +	Swig_error(input_file, line_number, "'%s' is multiply defined in the generated target language module in scope '%s'.\n", s, scope); +      else +	Swig_error(input_file, line_number, "'%s' is multiply defined in the generated target language module.\n", s); +      Swig_error(Getfile(c), Getline(c), "Previous declaration of '%s'\n", s); +      return 0; +    } +  } +  Setattr(symbols, s, n); +  return 1; +} + +/* ----------------------------------------------------------------------------- + * Language::addInterfaceSymbol() + * + * Adds a symbol entry into the target language symbol tables - for the interface + * feature only. + * Returns 1 if the symbol is added successfully. + * The scope is as per addSymbol. + * ----------------------------------------------------------------------------- */ + +int Language::addInterfaceSymbol(const String *interface_name, Node *n, const_String_or_char_ptr scope) { +  if (interface_name) { +    Node *existing_symbol = symbolLookup(interface_name, scope); +    if (existing_symbol) { +      String *proxy_class_name = Getattr(n, "sym:name"); +      Swig_error(input_file, line_number, "The interface feature name '%s' for proxy class '%s' is already defined in the generated target language module in scope '%s'.\n", +	  interface_name, proxy_class_name, scope); +      Swig_error(Getfile(existing_symbol), Getline(existing_symbol), "Previous declaration of '%s'\n", interface_name); +      return 0; +    } +    if (!addSymbol(interface_name, n, scope)) +      return 0; +  } +  return 1; +} + +/* ----------------------------------------------------------------------------- + * Language::symbolAddScope() + * + * Creates a scope (symbols Hash) for given name. This method is auxiliary, + * you don't have to call it - addSymbols will lazily create scopes automatically. + * If scope with given name already exists, then do nothing. + * Returns newly created (or already existing) scope. + * ----------------------------------------------------------------------------- */ +Hash* Language::symbolAddScope(const_String_or_char_ptr scope) { +  Hash *symbols = symbolScopeLookup(scope); +  if(!symbols) { +    // The order in which the following code is executed is important. In the Language +    // constructor addScope("") is called to create a top level scope. +    // Thus we must first add a symbols hash to symtab and only then add pseudo +    // symbols to the top-level scope. + +    // New scope which has not been added by the target language - lazily created. +    symbols = NewHash(); +    Setattr(symtabs, scope, symbols); + +    // Add the new scope as a symbol in the top level scope. +    // Alternatively the target language must add it in before attempting to add symbols into the scope. +    const_String_or_char_ptr top_scope = ""; +    Hash *topscope_symbols = Getattr(symtabs, top_scope); +    Hash *pseudo_symbol = NewHash(); +    Setattr(pseudo_symbol, "sym:scope", "1"); +    Setattr(topscope_symbols, scope, pseudo_symbol); +  } +  return symbols; +} + +/* ----------------------------------------------------------------------------- + * Language::symbolScopeLookup() + * + * Lookup and returns a symtable (hash) representing given scope. Hash contains + * all symbols in this scope. + * ----------------------------------------------------------------------------- */ +Hash* Language::symbolScopeLookup( const_String_or_char_ptr scope ) { +  Hash *symbols = Getattr(symtabs, scope ? scope : ""); +  return symbols; +} + +/* ----------------------------------------------------------------------------- + * Language::symbolScopePseudoSymbolLookup() + * + * For every scope there is a special pseudo-symbol in the top scope (""). It + * exists solely to detect name clashes. This pseudo symbol may contain a few properties, + * but more could be added. This is also true for the top level scope (""). + * It contains a pseudo symbol with name "" (empty). Pseudo symbol contains the + * following properties: + *   sym:scope = "1" - a flag that this is a scope pseudo symbol + * + * Pseudo symbols are a Hash*, not a Node*. + * There is no difference from symbolLookup() method except for signature + * and return type. + * ----------------------------------------------------------------------------- */ +Hash* Language::symbolScopePseudoSymbolLookup( const_String_or_char_ptr scope ) +{ +  /* Getting top scope */ +  const_String_or_char_ptr top_scope = ""; +  Hash *symbols = Getattr(symtabs, top_scope); +  return Getattr(symbols, scope); +} + +/* ----------------------------------------------------------------------------- + * Language::dumpSymbols() + * ----------------------------------------------------------------------------- */ + +void Language::dumpSymbols() { +  Printf(stdout, "LANGUAGE SYMBOLS start  =======================================\n"); + +  Node *table = symtabs; +  Iterator ki = First(table); +  while (ki.key) { +    String *k = ki.key; +    Printf(stdout, "===================================================\n"); +    Printf(stdout, "%s -\n", k); +    { +      Symtab *symtab = Getattr(table, k); +      Iterator it = First(symtab); +      while (it.key) { +	String *symname = it.key; +	Printf(stdout, "  %s\n", symname); +	it = Next(it); +      } +    } +    ki = Next(ki); +  } + +  Printf(stdout, "LANGUAGE SYMBOLS finish =======================================\n"); +} + +/* ----------------------------------------------------------------------------- + * Language::symbolLookup() + * ----------------------------------------------------------------------------- */ + +Node *Language::symbolLookup(const String *s, const_String_or_char_ptr scope) { +  Hash *symbols = Getattr(symtabs, scope ? scope : ""); +  if (!symbols) { +    return NULL; +  } +  return Getattr(symbols, s); +} + +/* ----------------------------------------------------------------------------- + * Language::classLookup() + * + * Tries to locate a class from a type definition + * ----------------------------------------------------------------------------- */ + +Node *Language::classLookup(const SwigType *s) { +  static Hash *classtypes = 0; + +  Node *n = 0; + +  /* Look in hash of cached values */ +  n = classtypes ? Getattr(classtypes, s) : 0; +  if (!n) { +    Symtab *stab = 0; +    SwigType *ty1 = SwigType_typedef_resolve_all(s); +    SwigType *ty2 = SwigType_strip_qualifiers(ty1); + +    String *base = SwigType_base(ty2); + +    Replaceall(base, "class ", ""); +    Replaceall(base, "struct ", ""); +    Replaceall(base, "union ", ""); + +    if (strncmp(Char(base), "::", 2) == 0) { +      String *oldbase = base; +      base = NewString(Char(base) + 2); +      Delete(oldbase); +    } + +    String *prefix = SwigType_prefix(ty2); + +    /* Do a symbol table search on the base type */ +    while (!n) { +      Hash *nstab; +      n = Swig_symbol_clookup(base, stab); +      if (!n) +	break; +      if (Strcmp(nodeType(n), "class") == 0) +	break; +      Node *sibling = n; +      while (sibling) { +       sibling = Getattr(sibling, "csym:nextSibling"); +       if (sibling && Strcmp(nodeType(sibling), "class") == 0) +         break; +      } +      if (sibling) +       break; +      n = parentNode(n); +      if (!n) +	break; +      nstab = Getattr(n, "sym:symtab"); +      n = 0; +      if ((!nstab) || (nstab == stab)) { +	break; +      } +      stab = nstab; +    } +    if (n) { +      /* Found a match.  Look at the prefix.  We only allow +         the cases where we want a proxy class for the particular type */ +      bool acceptable_prefix =  +	(Len(prefix) == 0) ||			      // simple type (pass by value) +	(Strcmp(prefix, "p.") == 0) ||		      // pointer +	(Strcmp(prefix, "r.") == 0) ||		      // reference +	(Strcmp(prefix, "z.") == 0) ||		      // rvalue reference +	SwigType_prefix_is_simple_1D_array(prefix);   // Simple 1D array (not arrays of pointers/references) +      // Also accept pointer by const reference, not non-const pointer reference +      if (!acceptable_prefix && (Strcmp(prefix, "r.p.") == 0)) { +	Delete(prefix); +	prefix = SwigType_prefix(ty1); +	acceptable_prefix = (Strncmp(prefix, "r.q(const", 9) == 0); +      } +      if (acceptable_prefix) { +	SwigType *cs = Copy(s); +	if (!classtypes) +	  classtypes = NewHash(); +	Setattr(classtypes, cs, n); +	Delete(cs); +      } else { +	n = 0; +      } +    } +    Delete(prefix); +    Delete(base); +    Delete(ty2); +    Delete(ty1); +  } +  if (n && (GetFlag(n, "feature:ignore") || Getattr(n, "feature:onlychildren"))) { +    n = 0; +  } + +  return n; +} + +/* ----------------------------------------------------------------------------- + * Language::enumLookup() + * + * Finds and returns the Node containing the enum declaration for the (enum)  + * type passed in. + * ----------------------------------------------------------------------------- */ + +Node *Language::enumLookup(SwigType *s) { +  static Hash *enumtypes = 0; + +  Node *n = 0; + +  /* Look in hash of cached values */ +  n = enumtypes ? Getattr(enumtypes, s) : 0; +  if (!n) { +    Symtab *stab = 0; +    SwigType *lt = SwigType_ltype(s); +    SwigType *ty1 = SwigType_typedef_resolve_all(lt); +    SwigType *ty2 = SwigType_strip_qualifiers(ty1); + +    String *base = SwigType_base(ty2); + +    Replaceall(base, "enum ", ""); +    String *prefix = SwigType_prefix(ty2); + +    if (strncmp(Char(base), "::", 2) == 0) { +      String *oldbase = base; +      base = NewString(Char(base) + 2); +      Delete(oldbase); +    } + +    /* Look for type in symbol table */ +    while (!n) { +      Hash *nstab; +      n = Swig_symbol_clookup(base, stab); +      if (!n) +	break; +      if (Equal(nodeType(n), "enum")) +	break; +      if (Equal(nodeType(n), "enumforward") && GetFlag(n, "enumMissing")) +	break; +      n = parentNode(n); +      if (!n) +	break; +      nstab = Getattr(n, "sym:symtab"); +      n = 0; +      if ((!nstab) || (nstab == stab)) { +	break; +      } +      stab = nstab; +    } +    if (n) { +      /* Found a match.  Look at the prefix.  We only allow simple types. */ +      if (Len(prefix) == 0) {	/* Simple type */ +	if (!enumtypes) +	  enumtypes = NewHash(); +	Setattr(enumtypes, Copy(s), n); +      } else { +	n = 0; +      } +    } +    Delete(prefix); +    Delete(base); +    Delete(ty2); +    Delete(ty1); +    Delete(lt); +  } +  if (n && (GetFlag(n, "feature:ignore"))) { +    n = 0; +  } + +  return n; +} + +/* ----------------------------------------------------------------------------- + * Language::allow_overloading() + * ----------------------------------------------------------------------------- */ + +void Language::allow_overloading(int val) { +  overloading = val; +} + +/* ----------------------------------------------------------------------------- + * Language::allow_multiple_input() + * ----------------------------------------------------------------------------- */ + +void Language::allow_multiple_input(int val) { +  multiinput = val; +} + +/* ----------------------------------------------------------------------------- + * Language::enable_cplus_runtime_mode() + * ----------------------------------------------------------------------------- */ + +void Language::enable_cplus_runtime_mode() { +  cplus_runtime = 1; +} + +/* ----------------------------------------------------------------------------- + * Language::cplus_runtime_mode() + * ----------------------------------------------------------------------------- */ + +int Language::cplus_runtime_mode() { +  return cplus_runtime; +} + +/* ----------------------------------------------------------------------------- + * Language::allow_directors() + * ----------------------------------------------------------------------------- */ + +void Language::allow_directors(int val) { +  directors = val; +} + +/* ----------------------------------------------------------------------------- + * Language::directorsEnabled() + * ----------------------------------------------------------------------------- */ + +int Language::directorsEnabled() const { +  return director_language && CPlusPlus && (directors || director_mode); +} + +/* ----------------------------------------------------------------------------- + * Language::allow_dirprot() + * ----------------------------------------------------------------------------- */ + +void Language::allow_dirprot(int val) { +  director_protected_mode = val; +} + +/* ----------------------------------------------------------------------------- + * Language::allow_allprotected() + * ----------------------------------------------------------------------------- */ + +void Language::allow_allprotected(int val) { +  all_protected_mode = val; +} + +/* ----------------------------------------------------------------------------- + * Language::dirprot_mode() + * ----------------------------------------------------------------------------- */ + +int Language::dirprot_mode() const { +  return directorsEnabled() ? director_protected_mode : 0; +} + +/* ----------------------------------------------------------------------------- + * Language::need_nonpublic_ctor() + * ----------------------------------------------------------------------------- */ + +int Language::need_nonpublic_ctor(Node *n) { +  /*  +     detects when a protected constructor is needed, which is always +     the case if 'dirprot' mode is used.  However, if that is not the +     case, we will try to strictly emit what is minimal to don't break +     the generated, while preserving compatibility with java, which +     always try to emit the default constructor. + +     rules: + +     - when dirprot mode is used, the protected constructors are +     always needed. + +     - the protected default constructor is always needed. + +     - if dirprot mode is not used, the protected constructors will be +     needed only if: + +     - there is no any public constructor in the class, and +     - there is no protected default constructor + +     In that case, all the declared protected constructors are +     needed since we don't know which one to pick up. + +     Note: given all the complications here, I am always in favor to +     always enable 'dirprot', since is the C++ idea of protected +     members, and use %ignore for the method you don't want to add in +     the director class. +   */ +  if (directorsEnabled()) { +    if (is_protected(n)) { +      if (dirprot_mode()) { +	/* when using dirprot mode, the protected constructors are +	   always needed */ +	return 1; +      } else { +	int is_default_ctor = !ParmList_numrequired(Getattr(n, "parms")); +	if (is_default_ctor) { +	  /* the default protected constructor is always needed, for java compatibility */ +	  return 1; +	} else { +	  /* check if there is a public constructor */ +	  Node *parent = Swig_methodclass(n); +	  int public_ctor = Getattr(parent, "allocate:default_constructor") +	      || Getattr(parent, "allocate:public_constructor"); +	  if (!public_ctor) { +	    /* if not, the protected constructor will be needed only +	       if there is no protected default constructor declared */ +	    int no_prot_default_ctor = !Getattr(parent, "allocate:default_base_constructor"); +	    return no_prot_default_ctor; +	  } +	} +      } +    } +  } +  return 0; +} + +/* ----------------------------------------------------------------------------- + * Language::need_nonpublic_member() + * ----------------------------------------------------------------------------- */ +int Language::need_nonpublic_member(Node *n) { +  if (directorsEnabled() && DirectorClassName) { +    if (is_protected(n)) { +      if (dirprot_mode()) { +	/* when using dirprot mode, the protected members are always needed. */ +	return 1; +      } else { +	/* if the method is pure virtual, we need it. */ +	int pure_virtual = (Cmp(Getattr(n, "value"), "0") == 0); +	return pure_virtual; +      } +    } +  } +  return 0; +} + + +/* ----------------------------------------------------------------------------- + * Language::is_smart_pointer() + * ----------------------------------------------------------------------------- */ + +int Language::is_smart_pointer() const { +  return SmartPointer; +} + +/* ----------------------------------------------------------------------------- + * Language::makeParameterName() + * + * Inputs:  + *   n - Node + *   p - parameter node + *   arg_num - parameter argument number + *   setter  - set this flag when wrapping variables + * Return: + *   arg - a unique parameter name + * ----------------------------------------------------------------------------- */ +String *Language::makeParameterName(Node *n, Parm *p, int arg_num, bool setter) const { + +  String *arg = 0; +  String *pn = Getattr(p, "name"); + +  // Check if parameter name is a duplicate. +  int count = 0; +  ParmList *plist = Getattr(n, "parms"); +  while (plist) { +    if ((Cmp(pn, Getattr(plist, "name")) == 0)) +      count++; +    plist = nextSibling(plist); +  } + +  // If the parameter has no name at all or has a non-unique name, replace it with "argN". +  if (!pn || count > 1) { +    arg = NewStringf("arg%d", arg_num); +  } else { +    // Otherwise, try to use the original C name, but modify it if necessary to avoid conflicting with the language keywords. +    arg = Swig_name_make(p, 0, pn, 0, 0); +  } + +  if (setter && Cmp(arg, "self") != 0) { +    // Some languages (C#) insist on calling the input variable "value" while +    // others (D, Java) could, in principle, use something different but this +    // would require more work, and so we just use "value" for them too. +    // For setters the parameter name sometimes includes C++ scope resolution which needs removing. +    Delete(arg); +    arg = NewString("value"); +  } + +  return arg; +} + +/* ----------------------------------------------------------------------------- + * Language::() + * ----------------------------------------------------------------------------- */ + +bool Language::isNonVirtualProtectedAccess(Node *n) const { +  // Ideally is_non_virtual_protected_access() would contain all this logic, see +  // comments therein about vtable.  +  return DirectorClassName && is_non_virtual_protected_access(n); +} + +/* ----------------------------------------------------------------------------- + * Language::extraDirectorProtectedCPPMethodsRequired() + * ----------------------------------------------------------------------------- */ + +bool Language::extraDirectorProtectedCPPMethodsRequired() const { +  return true; +} + +/* ----------------------------------------------------------------------------- + * Language::nestedClassesSupport() + * ----------------------------------------------------------------------------- */ + +Language::NestedClassSupport Language::nestedClassesSupport() const { +  return NCS_Unknown; +} + +/* ----------------------------------------------------------------------------- + * Language::kwargsSupport() + * ----------------------------------------------------------------------------- */ + +bool Language::kwargsSupport() const { +  return false; +} + +/* ----------------------------------------------------------------------------- + * Language::is_wrapping_class() + * ----------------------------------------------------------------------------- */ + +int Language::is_wrapping_class() const { +  return InClass; +} + +/* ----------------------------------------------------------------------------- + * Language::getCurrentClass() + * ----------------------------------------------------------------------------- */ + +Node *Language::getCurrentClass() const { +  return CurrentClass; +} + +/* ----------------------------------------------------------------------------- + * Language::getNSpace() + * ----------------------------------------------------------------------------- */ + +String *Language::getNSpace() const { +  return NSpace; +} + +/* ----------------------------------------------------------------------------- + * Language::getClassName() + * ----------------------------------------------------------------------------- */ + +String *Language::getClassName() const { +  return ClassName; +} + +/* ----------------------------------------------------------------------------- + * Language::getClassPrefix() + * ----------------------------------------------------------------------------- */ + +String *Language::getClassPrefix() const { +  return ClassPrefix; +} + +/* ----------------------------------------------------------------------------- + * Language::getEnumClassPrefix() + * ----------------------------------------------------------------------------- */ + +String *Language::getEnumClassPrefix() const { +  return EnumClassPrefix; +} + +/* ----------------------------------------------------------------------------- + * Language::getClassType() + * ----------------------------------------------------------------------------- */ + +String *Language::getClassType() const { +  return ClassType; +} + +/* ----------------------------------------------------------------------------- + * Language::abstractClassTest() + * ----------------------------------------------------------------------------- */ +//#define SWIG_DEBUG +int Language::abstractClassTest(Node *n) { +  /* check for non public operator new */ +  if (GetFlag(n, "feature:notabstract")) +    return 0; +  if (Getattr(n, "allocate:nonew")) +    return 1; + +  // A class cannot be instantiated if one of its bases has a private destructor +  // Note that if the above does not hold the class can be instantiated if its own destructor is private +  List *bases = Getattr(n, "bases"); +  if (bases) { +    for (int i = 0; i < Len(bases); i++) { +      Node *b = Getitem(bases, i); +      if (GetFlag(b, "allocate:private_destructor")) +	return 1; +    } +  } + +  /* now check for the rest */ +  List *abstracts = Getattr(n, "abstracts"); +  if (!abstracts) +    return 0; +  int labs = Len(abstracts); +#ifdef SWIG_DEBUG +  List *allbases = Getattr(n, "allbases"); +  Printf(stderr, "testing %s %d %d\n", Getattr(n, "name"), labs, Len(allbases)); +#endif +  if (!labs) +    return 0;			/*strange, but need to be fixed */ +  if (abstracts && !directorsEnabled()) +    return 1; +  if (!GetFlag(n, "feature:director")) +    return 1; + +  Node *dirabstract = 0; +  Node *vtable = Getattr(n, "vtable"); +  if (vtable) { +#ifdef SWIG_DEBUG +    Printf(stderr, "vtable %s %d %d\n", Getattr(n, "name"), Len(vtable), labs); +#endif +    for (int i = 0; i < labs; i++) { +      Node *ni = Getitem(abstracts, i); +      String *method_id = vtable_method_id(ni); +      if (!method_id) +	continue; +      bool exists_item = false; +      int len = Len(vtable); +      for (int i = 0; i < len; i++) { +	Node *item = Getitem(vtable, i); +	String *check_item = Getattr(item, "vmid"); +	if (Strcmp(method_id, check_item) == 0) { +	  exists_item = true; +	  break; +	} +      } +#ifdef SWIG_DEBUG +      Printf(stderr, "method %s %d\n", method_id, exists_item ? 1 : 0); +#endif +      Delete(method_id); +      if (!exists_item) { +	dirabstract = ni; +	break; +      } +    } +    if (dirabstract) { +      if (is_public(dirabstract)) { +	Swig_warning(WARN_LANG_DIRECTOR_ABSTRACT, Getfile(n), Getline(n), +		     "Director class '%s' is abstract, abstract method '%s' is not accessible, maybe due to multiple inheritance or 'nodirector' feature\n", +		     SwigType_namestr(Getattr(n, "name")), Getattr(dirabstract, "name")); +      } else { +	Swig_warning(WARN_LANG_DIRECTOR_ABSTRACT, Getfile(n), Getline(n), +		     "Director class '%s' is abstract, abstract method '%s' is private\n", SwigType_namestr(Getattr(n, "name")), Getattr(dirabstract, "name")); +      } +      return 1; +    } +  } else { +    return 1; +  } +  return 0; +} + +void Language::setSubclassInstanceCheck(String *nc) { +  none_comparison = nc; +} + +void Language::setOverloadResolutionTemplates(String *argc, String *argv) { +  Delete(argc_template_string); +  argc_template_string = Copy(argc); +  Delete(argv_template_string); +  argv_template_string = Copy(argv); +} + +int Language::is_assignable(Node *n) { +  if (GetFlag(n, "feature:immutable")) +    return 0; +  SwigType *type = Getattr(n, "type"); +  Node *cn = 0; +  SwigType *ftd = SwigType_typedef_resolve_all(type); +  SwigType *td = SwigType_strip_qualifiers(ftd); +  if (SwigType_type(td) == T_USER) { +    cn = Swig_symbol_clookup(td, 0); +    if (cn) { +      if ((Strcmp(nodeType(cn), "class") == 0)) { +	if (Getattr(cn, "allocate:noassign")) { +	  SetFlag(n, "feature:immutable"); +	  Delete(ftd); +	  Delete(td); +	  return 0; +	} +      } +    } +  } +  Delete(ftd); +  Delete(td); +  return 1; +} + +String *Language::runtimeCode() { +  return NewString(""); +} + +String *Language::defaultExternalRuntimeFilename() { +  return 0; +} + +/* ----------------------------------------------------------------------------- + * Language::replaceSpecialVariables() + * + * Language modules should implement this if special variables are to be handled + * correctly in the $typemap(...) special variable macro. + * method - typemap method name + * tm - string containing typemap contents + * parm - a parameter describing the typemap type to be handled + * ----------------------------------------------------------------------------- */ +void Language::replaceSpecialVariables(String *method, String *tm, Parm *parm) { +  (void)method; +  (void)tm; +  (void)parm; +} + +Language *Language::instance() { +  return this_; +} + +Hash *Language::getClassHash() const { +  return classhash; +} + diff --git a/contrib/tools/swig/Source/Modules/lua.cxx b/contrib/tools/swig/Source/Modules/lua.cxx new file mode 100644 index 00000000000..d3cf96b5262 --- /dev/null +++ b/contrib/tools/swig/Source/Modules/lua.cxx @@ -0,0 +1,2240 @@ +/* ----------------------------------------------------------------------------- + * This file is part of SWIG, which is licensed as a whole under version 3  + * (or any later version) of the GNU General Public License. Some additional + * terms also apply to certain portions of SWIG. The full details of the SWIG + * license and copyrights can be found in the LICENSE and COPYRIGHT files + * included with the SWIG source code as distributed by the SWIG developers + * and at https://www.swig.org/legal.html. + * + * lua.cxx + * + * Lua language module for SWIG. + * ----------------------------------------------------------------------------- */ + +/* NEW LANGUAGE NOTE: + * ver001 +   this is simply a copy of tcl8.cxx, which has been renamed + * ver002 +   all non essential code commented out, program now does virtually nothing +   it prints to stderr the list of functions to wrap, but does not create +   the XXX_wrap.c file + * ver003 +   added back top(), still prints the list of fns to stderr +   but now creates a rather empty XXX_wrap.c with some basic boilerplate code + * ver004 +   very basic version of functionWrapper() +   also uncommented usage_string() to keep compiler happy +   this will start producing proper looking code soon (I hope) +   produced the wrapper code, but without any type conversion (in or out) +   generates a few warning because of no wrappering +   does not generate SWIG_init() +   reason for this is that lua.swg is empty +   we will need to add code into this to make it work + * ver005/6 +   massive rework, basing work on the pike module instead of tcl +   (pike module it only 1/3 of the size)(though not as complete) + * ver007 +   added simple type checking + * ver008 +   INPUT, OUTPUT, INOUT typemaps handled (though not all types yet) + * ver009 +   class support: ok for basic types, but methods still TDB +   (code is VERY messed up & needs to be cleaned) + * ver010 +   Added support for embedded Lua. Try swig -lua -help for more information +*/ + +#include "swigmod.h" +#include "cparse.h" + +/**** Diagnostics: +  With the #define REPORT(), you can change the amount of diagnostics given +  This helps me search the parse tree & figure out what is going on inside SWIG +  (because it's not clear or documented) +*/ +#define REPORT(T,D)		// no info: +//#define REPORT(T,D)   {Printf(stdout,T"\n");} // only title +//#define REPORT(T,D)           {Printf(stdout,T" %p\n",n);} // title & pointer +//#define REPORT(T,D)   {Printf(stdout,T"\n");display_mapping(D);}      // the works +//#define REPORT(T,D)   {Printf(stdout,T"\n");if(D)Swig_print_node(D);}      // the works + +void display_mapping(DOH *d) { +  if (d == 0 || !DohIsMapping(d)) +    return; +  for (Iterator it = First(d); it.item; it = Next(it)) { +    if (DohIsString(it.item)) +      Printf(stdout, "  %s = %s\n", it.key, it.item); +    else if (DohIsMapping(it.item)) +      Printf(stdout, "  %s = <mapping>\n", it.key); +    else if (DohIsSequence(it.item)) +      Printf(stdout, "  %s = <sequence>\n", it.key); +    else +      Printf(stdout, "  %s = <unknown>\n", it.key); +  } +} + +extern "C" +{ +  static int compareByLen(const DOH *f, const DOH *s) { +    return Len(s) - Len(f); +  } +} + + +/* NEW LANGUAGE NOTE:*********************************************** + most of the default options are handled by SWIG + you can add new ones here + (though for now I have not bothered) +NEW LANGUAGE NOTE:END ************************************************/ +static const char *usage = "\ +Lua Options (available with -lua)\n\ +     -elua           - Generates LTR compatible wrappers for smaller devices running elua\n\ +     -eluac          - LTR compatible wrappers in \"crass compress\" mode for elua\n\ +     -elua-emulate   - Emulates behaviour of eLua. Useful only for testing.\n\ +                       Incompatible with -elua/-eluac options.\n\ +     -nomoduleglobal - Do not register the module name as a global variable \n\ +                       but return the module table from calls to require.\n\ +     -no-old-metatable-bindings\n\ +                     - Disable support for old-style bindings name generation, some\n\ +                       old-style members scheme etc.\n\ +     -squash-bases   - Squashes symbols from all inheritance tree of a given class\n\ +                       into itself. Emulates pre-SWIG3.0 inheritance. Insignificantly\n\ +                       speeds things up, but increases memory consumption.\n\ +\n"; + +static int nomoduleglobal = 0; +static int elua_ltr = 0; +static int eluac_ltr = 0; +static int elua_emulate = 0; +static int squash_bases = 0; +/* The new metatable bindings were introduced in SWIG 3.0.0. + * old_metatable_bindings in v2:  + *                    1. static methods will be put into the scope their respective class + *                    belongs to as well as into the class scope itself. (only for classes without %nspace given) + *                    2. The layout in elua mode is somewhat different + */ +static int old_metatable_bindings = 1; +static int old_compatible_names = 1; // This flag can temporarily disable backward compatible names generation if old_metatable_bindings is enabled + +/* NEW LANGUAGE NOTE:*********************************************** + To add a new language, you need to derive your class from + Language and the overload various virtual functions + (more on this as I figure it out) +NEW LANGUAGE NOTE:END ************************************************/ + +class LUA:public Language { +private: + +  File *f_begin; +  File *f_runtime; +  File *f_header; +  File *f_wrappers; +  File *f_init; +  File *f_initbeforefunc; +  String *s_luacode;		// luacode to be called during init +  String *module;		//name of the module + +  // Parameters for current class. NIL if not parsing class +  int have_constructor; +  int have_destructor; +  String *destructor_action; +  // This variable holds the name of the current class in Lua. Usually it is +  // the same as C++ class name, but rename directives can change it. +  String *proxy_class_name; +  // This is a so called fully qualified symname - the above proxy class name +  // prepended with class namespace. If class Lua name is the same as class C++ name, +  // then it is basically C++ fully qualified name with colons replaced with dots. +  String *full_proxy_class_name;	 +  // All static methods and/or variables are treated as if they were in the +  // special C++ namespace $(classname).SwigStatic. This is internal mechanism only +  // and is not visible to user in any manner. This variable holds the name +  // of such pseudo-namespace a.k.a the result of above expression evaluation +  String *class_static_nspace; +  // This variable holds the name of generated C function that acts as a constructor +  // for the currently parsed class. +  String *constructor_name; + +  // Many wrappers forward calls to each other, for example staticmembervariableHandler +  // forwards calls to variableHandler, which, in turn, makes to call to functionWrapper. +  // In order to access information about whether it is a static member of class or just  +  // a plain old variable, the current array is kept and used as a 'log' of the call stack. +  enum TState { +    NO_CPP, +    VARIABLE, +    GLOBAL_FUNC, +    GLOBAL_VAR, +    MEMBER_FUNC, +    CONSTRUCTOR, +    DESTRUCTOR, +    MEMBER_VAR, +    STATIC_FUNC, +    STATIC_VAR, +    STATIC_CONST,		// enums and things like static const int x = 5; +    ENUM_CONST, // This is only needed for backward compatibility in C mode + +    STATES_COUNT +  }; +  bool current[STATES_COUNT]; + +public: + +  /* --------------------------------------------------------------------- +   * LUA() +   * +   * Initialize member data +   * --------------------------------------------------------------------- */ + +   LUA(): +      f_begin(0), +      f_runtime(0), +      f_header(0), +      f_wrappers(0), +      f_init(0), +      f_initbeforefunc(0), +      s_luacode(0), +      module(0), +      have_constructor(0), +      have_destructor(0), +      destructor_action(0), +      proxy_class_name(0), +      full_proxy_class_name(0), +      class_static_nspace(0), +      constructor_name(0) { +    for (int i = 0; i < STATES_COUNT; i++) +      current[i] = false; +  } + +  /* NEW LANGUAGE NOTE:*********************************************** +     This is called to initialise the system & read any command line args +     most of this is boilerplate code, except the command line args +     which depends upon what args your code supports +     NEW LANGUAGE NOTE:END *********************************************** */ + +  /* --------------------------------------------------------------------- +   * main() +   * +   * Parse command line options and initializes variables. +   * --------------------------------------------------------------------- */ + +  virtual void main(int argc, char *argv[]) { + +    /* Set location of SWIG library */ +    SWIG_library_directory("lua"); + +    /* Look for certain command line options */ +    for (int i = 1; i < argc; i++) { +      if (argv[i]) { +	if (strcmp(argv[i], "-help") == 0) {	// usage flags +	  fputs(usage, stdout); +	} else if (strcmp(argv[i], "-nomoduleglobal") == 0) { +	  nomoduleglobal = 1; +	  Swig_mark_arg(i); +	} else if (strcmp(argv[i], "-elua") == 0) { +	  elua_ltr = 1; +	  Swig_mark_arg(i); +	} else if (strcmp(argv[i], "-eluac") == 0) { +	  eluac_ltr = 1; +	  Swig_mark_arg(i); +	} else if (strcmp(argv[i], "-no-old-metatable-bindings") == 0) { +	  Swig_mark_arg(i); +	  old_metatable_bindings = 0; +	} else if (strcmp(argv[i], "-squash-bases") == 0) { +	  Swig_mark_arg(i); +	  squash_bases = 1; +	} else if (strcmp(argv[i], "-elua-emulate") == 0) { +	  Swig_mark_arg(i); +	  elua_emulate = 1; +	} +      } +    } + +    if (elua_emulate && (eluac_ltr || elua_ltr )) { +      Printf(stderr, "Cannot have -elua-emulate with either -eluac or -elua\n"); +      Swig_arg_error(); +    } + +    // Set elua_ltr if elua_emulate is requested +    if(elua_emulate) +      elua_ltr = 1; + +    /* NEW LANGUAGE NOTE:*********************************************** +       This is the boilerplate code, setting a few #defines +       and which lib directory to use +       the SWIG_library_directory() is also boilerplate code +       but it always seems to be the first line of code +       NEW LANGUAGE NOTE:END *********************************************** */ +    /* Add a symbol to the parser for conditional compilation */ +    Preprocessor_define("SWIGLUA 1", 0); + +    /* Set language-specific configuration file */ +    SWIG_config_file("lua.swg"); + +    /* Set typemap language */ +    SWIG_typemap_lang("lua"); + +    /* Enable overloaded methods support */ +    allow_overloading(); +  } + + + + +  /* NEW LANGUAGE NOTE:*********************************************** +     After calling main, SWIG parses the code to wrap (I believe) +     then calls top() +     in this is more boilerplate code to set everything up +     and a call to Language::top() +     which begins the code generations by calling the member fns +     after all that is more boilerplate code to close all down +     (overall there is virtually nothing here that needs to be edited +     just use as is) +     NEW LANGUAGE NOTE:END *********************************************** */ +  /* --------------------------------------------------------------------- +   * top() +   * --------------------------------------------------------------------- */ + +  virtual int top(Node *n) { +    /* Get the module name */ +    module = Getattr(n, "name"); + +    /* Get the output file name */ +    String *outfile = Getattr(n, "outfile"); + +    /* Open the output file */ +    f_begin = NewFile(outfile, "w", SWIG_output_files()); +    if (!f_begin) { +      FileErrorDisplay(outfile); +      Exit(EXIT_FAILURE); +    } +    f_runtime = NewString(""); +    f_init = NewString(""); +    f_header = NewString(""); +    f_wrappers = NewString(""); +    f_initbeforefunc = NewString(""); + +    /* Register file targets with the SWIG file handler */ +    Swig_register_filebyname("header", f_header); +    Swig_register_filebyname("wrapper", f_wrappers); +    Swig_register_filebyname("begin", f_begin); +    Swig_register_filebyname("runtime", f_runtime); +    Swig_register_filebyname("init", f_init); +    Swig_register_filebyname("initbeforefunc", f_initbeforefunc); + + +    s_luacode = NewString(""); +    Swig_register_filebyname("luacode", s_luacode); + +    current[NO_CPP] = true; + +    /* Standard stuff for the SWIG runtime section */ +    Swig_banner(f_begin); + +    Swig_obligatory_macros(f_runtime, "LUA"); + +    emitLuaFlavor(f_runtime); + +    if (nomoduleglobal) { +      Printf(f_runtime, "#define SWIG_LUA_NO_MODULE_GLOBAL\n"); +    } else { +      Printf(f_runtime, "#define SWIG_LUA_MODULE_GLOBAL\n"); +    } +    if (squash_bases) +      Printf(f_runtime, "#define SWIG_LUA_SQUASH_BASES\n"); + +    //    if (NoInclude) { +    //      Printf(f_runtime, "#define SWIG_NOINCLUDE\n"); +    //    } + +    Printf(f_runtime, "\n"); + +    //String *init_name = NewStringf("%(title)s_Init", module); +    //Printf(f_header, "#define SWIG_init    %s\n", init_name); +    //Printf(f_header, "#define SWIG_name    \"%s\"\n", module); +    /* SWIG_import is a special function name for importing within Lua5.1 */ +    //Printf(f_header, "#define SWIG_import  luaopen_%s\n\n", module); +    Printf(f_header, "#define SWIG_name      \"%s\"\n", module); +    Printf(f_header, "#define SWIG_init      luaopen_%s\n", module); +    Printf(f_header, "#define SWIG_init_user luaopen_%s_user\n\n", module); +    Printf(f_header, "#define SWIG_LUACODE   luaopen_%s_luacode\n", module); + +    Printf(f_wrappers, "#ifdef __cplusplus\nextern \"C\" {\n#endif\n"); + +    /* %init code inclusion, effectively in the SWIG_init function */ +    Printf(f_init, "void SWIG_init_user(lua_State* L)\n{\n"); +    Language::top(n); +    Printf(f_init, "/* exec Lua code if applicable */\nSWIG_Lua_dostring(L,SWIG_LUACODE);\n"); +    Printf(f_init, "}\n"); + +    // Done.  Close up the module & write to the wrappers +    closeNamespaces(f_wrappers); +    Printf(f_wrappers, "#ifdef __cplusplus\n}\n#endif\n"); + +    SwigType_emit_type_table(f_runtime, f_wrappers); + +    /* NEW LANGUAGE NOTE:*********************************************** +       this basically combines several of the strings together +       and then writes it all to a file +       NEW LANGUAGE NOTE:END *********************************************** */ +    Dump(f_runtime, f_begin); +    Dump(f_header, f_begin); +    Dump(f_wrappers, f_begin); +    Dump(f_initbeforefunc, f_begin); +    /* for the Lua code it needs to be properly escaped to be added into the C/C++ code */ +    escapeCode(s_luacode); +    Printf(f_begin, "const char* SWIG_LUACODE=\n  \"%s\";\n\n", s_luacode); +    Wrapper_pretty_print(f_init, f_begin); +    /* Close all of the files */ +    Delete(s_luacode); +    Delete(f_header); +    Delete(f_wrappers); +    Delete(f_init); +    Delete(f_initbeforefunc); +    Delete(f_runtime); +    Delete(f_begin); + +    /* Done */ +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * importDirective() +   * ------------------------------------------------------------ */ + +  virtual int importDirective(Node *n) { +    return Language::importDirective(n); +  } + +  /* ------------------------------------------------------------ +   * cDeclaration() +   * It copies sym:name to lua:name to preserve its original value +   * ------------------------------------------------------------ */ + +  virtual int cDeclaration(Node *n) { +    // class 'Language' is messing with symname in a really heavy way. +    // Although documentation states that sym:name is a name in +    // the target language space, it is not true. sym:name and +    // its derivatives are used in various places, including +    // behind-the-scene C code generation. The best way is not to +    // touch it at all. +    // But we need to know what was the name of function/variable +    // etc that user desired, that's why we store correct symname +    // as lua:name +    String *symname = Getattr(n, "sym:name"); +    if (symname) +      Setattr(n, "lua:name", symname); +    return Language::cDeclaration(n); +  } +  virtual int constructorDeclaration(Node *n) { +    Setattr(n, "lua:name", Getattr(n, "sym:name")); +    return Language::constructorDeclaration(n); +  } +  virtual int destructorDeclaration(Node *n) { +    Setattr(n, "lua:name", Getattr(n, "sym:name")); +    return Language::destructorDeclaration(n); +  } +  /* NEW LANGUAGE NOTE:*********************************************** +     This is it! +     you get this one right, and most of your work is done +     but it's going to take some file to get it working right +     quite a bit of this is generally boilerplate code +     (or stuff I don't understand) +     that which matters will have extra added comments +     NEW LANGUAGE NOTE:END *********************************************** */ +  /* --------------------------------------------------------------------- +   * functionWrapper() +   * +   * Create a function declaration and register it with the interpreter. +   * --------------------------------------------------------------------- */ + +  /* ----------------------------------------------------------------------- +   * registerMethod() +   * +   * Determines wrap name of a method, its scope etc and calls +   * registerMethod overload with correct arguments +   * Overloaded variant adds method to the "methods" array of specified lua scope/class +   * ---------------------------------------------------------------------- */ + +  void registerMethod(Node *n, bool overwrite = false, String *overwriteLuaScope = 0) { +    String *symname = Getattr(n, "sym:name"); +    assert(symname); + +    if (Getattr(n, "sym:nextSibling")) +      return; + +    // Lua scope. It is not symbol NSpace, it is the actual key to retrieve getCArraysHash. +    String *luaScope = luaCurrentSymbolNSpace(); +    if (overwrite) +      luaScope = overwriteLuaScope; + +    String *wrapname = 0; +    String *mrename; +    if (current[NO_CPP] || !getCurrentClass()) { +      mrename = symname; +    } else { +      assert(!current[NO_CPP]); +      if (current[STATIC_FUNC] || current[MEMBER_FUNC]) { +	mrename = Swig_name_member(getNSpace(), getClassPrefix(), symname); +      } else { +	mrename = symname; +      } +    } +    wrapname = Swig_name_wrapper(mrename); +    registerMethod(n, wrapname, luaScope); +  } + +  /* ----------------------------------------------------------------------- +   * registerMethod() +   * +   * Add method to the "methods" C array of given namespace/class +   * ---------------------------------------------------------------------- */ + +  void registerMethod(Node *n, String* wname, String *luaScope) { +    assert(n); +    Hash *nspaceHash = getCArraysHash(luaScope); +    String *s_ns_methods_tab = Getattr(nspaceHash, "methods"); +    String *lua_name = Getattr(n, "lua:name"); +    if (elua_ltr || eluac_ltr) +      Printv(s_ns_methods_tab, tab4, "{LSTRKEY(\"", lua_name, "\")", ", LFUNCVAL(", wname, ")", "},\n", NIL); +    else +      Printv(s_ns_methods_tab, tab4, "{ \"", lua_name, "\", ", wname, "},\n", NIL); +    // Add to the metatable if method starts with '__' +    const char * tn = Char(lua_name); +    if (tn[0]=='_' && tn[1] == '_' && !eluac_ltr) { +      String *metatable_tab = Getattr(nspaceHash, "metatable"); +      assert(metatable_tab); +      if (elua_ltr) +	Printv(metatable_tab, tab4, "{LSTRKEY(\"", lua_name, "\")", ", LFUNCVAL(", wname, ")", "},\n", NIL); +      else +	Printv(metatable_tab, tab4, "{ \"", lua_name, "\", ", wname, "},\n", NIL); +    } +  } + +  virtual int functionWrapper(Node *n) { +    REPORT("functionWrapper", n); + +    String *name = Getattr(n, "name"); +    String *iname = Getattr(n, "sym:name"); +    String *lua_name = Getattr(n, "lua:name"); +    assert(lua_name); +    SwigType *d = Getattr(n, "type"); +    ParmList *l = Getattr(n, "parms"); +    Parm *p; +    String *tm; +    int i; +    //Printf(stdout,"functionWrapper %s %s %d\n",name,iname,current); + +    String *overname = 0; +    if (Getattr(n, "sym:overloaded")) { +      overname = Getattr(n, "sym:overname"); +    } else { +      if (!luaAddSymbol(lua_name, n)) { +	return SWIG_ERROR; +      } +    } + +    /* NEW LANGUAGE NOTE:*********************************************** +       the wrapper object holds all the wrapper code +       we need to add a couple of local variables +       NEW LANGUAGE NOTE:END *********************************************** */ +    Wrapper *f = NewWrapper(); +    Wrapper_add_local(f, "SWIG_arg", "int SWIG_arg = 0"); + + +    String *wname = Swig_name_wrapper(iname); +    if (overname) { +      Append(wname, overname); +    } +    if (current[CONSTRUCTOR]) { +      if (constructor_name != 0) +	Delete(constructor_name); +      constructor_name = Copy(wname); +    } + +    /* NEW LANGUAGE NOTE:*********************************************** +       the format of a lua fn is: +       static int wrap_XXX(lua_State* L){...} +       this line adds this into the wrapper code +       NEW LANGUAGE NOTE:END *********************************************** */ +    Printv(f->def, "static int ", wname, "(lua_State* L) {", NIL); +    // SWIG_fail in lua leads to a call to lua_error() which calls longjmp() +    // which means the destructors of any live function-local C++ objects won't +    // get run.  To avoid this happening, we wrap almost everything in the +    // function in a block, and end that right before lua_error() at which +    // point those destructors will get called. +    if (CPlusPlus) Append(f->def, "\n{"); + +    /* NEW LANGUAGE NOTE:*********************************************** +       this prints the list of args, eg for a C fn +       int gcd(int x,int y); +       it will print +       int arg1; +       int arg2; +       NEW LANGUAGE NOTE:END *********************************************** */ +    /* Write code to extract function parameters. */ +    emit_parameter_variables(l, f); + +    /* Attach the standard typemaps */ +    emit_attach_parmmaps(l, f); +    Setattr(n, "wrap:parms", l); + +    /* Get number of required and total arguments */ +    int num_arguments = emit_num_arguments(l); +    int num_required = emit_num_required(l); +    int varargs = emit_isvarargs(l); + +    // Check if we have to ignore arguments that are passed by LUA. +    // Needed for unary minus, where lua passes two arguments and +    // we have to ignore the second. + +    int args_to_ignore = 0; +    if (Getattr(n, "lua:ignore_args")) { +      args_to_ignore = GetInt(n, "lua:ignore_args"); +    } + + +    /* NEW LANGUAGE NOTE:*********************************************** +       from here on in, it gets rather hairy +       this is the code to convert from the scripting language to C/C++ +       some of the stuff will refer to the typemaps code written in your swig file +       (lua.swg), and some is done in the code here +       I suppose you could do all the conversion in C, but it would be a nightmare to do +       NEW LANGUAGE NOTE:END *********************************************** */ +    /* Generate code for argument marshalling */ +    //    String *description = NewString(""); +    /* NEW LANGUAGE NOTE:*********************************************** +       argument_check is a new feature I added to check types of arguments: +       eg for int gcd(int,int) +       I want to check that arg1 & arg2 really are integers +       NEW LANGUAGE NOTE:END *********************************************** */ +    String *argument_check = NewString(""); +    String *argument_parse = NewString(""); +    String *checkfn = NULL; +    char source[64]; +    Printf(argument_check, "SWIG_check_num_args(\"%s\",%d,%d)\n", Swig_name_str(n), num_required + args_to_ignore, num_arguments + args_to_ignore); + +    for (i = 0, p = l; i < num_arguments; i++) { + +      while (checkAttribute(p, "tmap:in:numinputs", "0")) { +	p = Getattr(p, "tmap:in:next"); +      } + +      SwigType *pt = Getattr(p, "type"); +      /* Look for an input typemap */ +      sprintf(source, "%d", i + 1); +      if ((tm = Getattr(p, "tmap:in"))) { +	Replaceall(tm, "$input", source); +	Setattr(p, "emit:input", source); +	if (Getattr(p, "wrap:disown") || (Getattr(p, "tmap:in:disown"))) { +	  Replaceall(tm, "$disown", "SWIG_POINTER_DISOWN"); +	} else { +	  Replaceall(tm, "$disown", "0"); +	} +	/* NEW LANGUAGE NOTE:*********************************************** +	   look for a 'checkfn' typemap +	   this an additional parameter added to the in typemap +	   if found the type will be tested for +	   this will result in code either in the +	   argument_check or argument_parse string +	   NEW LANGUAGE NOTE:END *********************************************** */ +	if ((checkfn = Getattr(p, "tmap:in:checkfn"))) { +	  if (i < num_required) { +	    Printf(argument_check, "if(!%s(L,%s))", checkfn, source); +	  } else { +	    Printf(argument_check, "if(lua_gettop(L)>=%s && !%s(L,%s))", source, checkfn, source); +	  } +	  Printf(argument_check, " SWIG_fail_arg(\"%s\",%s,\"%s\");\n", Swig_name_str(n), source, SwigType_str(pt, 0)); +	} +	/* NEW LANGUAGE NOTE:*********************************************** +	   lua states the number of arguments passed to a function using the fn +	   lua_gettop() +	   we can use this to deal with default arguments +	   NEW LANGUAGE NOTE:END *********************************************** */ +	if (i < num_required) { +	  Printf(argument_parse, "%s\n", tm); +	} else { +	  Printf(argument_parse, "if(lua_gettop(L)>=%s){%s}\n", source, tm); +	} +	p = Getattr(p, "tmap:in:next"); +	continue; +      } else { +	/* NEW LANGUAGE NOTE:*********************************************** +	   // why is this code not called when I don't have a typemap? +	   // instead of giving a warning, no code is generated +	   NEW LANGUAGE NOTE:END *********************************************** */ +	Swig_warning(WARN_TYPEMAP_IN_UNDEF, input_file, line_number, "Unable to use type %s as a function argument.\n", SwigType_str(pt, 0)); +	break; +      } +    } + +    // add all argcheck code +    Printv(f->code, argument_check, argument_parse, NIL); + +    /* Check for trailing varargs */ +    if (varargs) { +      if (p && (tm = Getattr(p, "tmap:in"))) { +	Replaceall(tm, "$input", "varargs"); +	Printv(f->code, tm, "\n", NIL); +      } +    } + +    /* Insert constraint checking code */ +    for (p = l; p;) { +      if ((tm = Getattr(p, "tmap:check"))) { +	Printv(f->code, tm, "\n", NIL); +	p = Getattr(p, "tmap:check:next"); +      } else { +	p = nextSibling(p); +      } +    } + +    /* Insert cleanup code */ +    String *cleanup = NewString(""); +    for (p = l; p;) { +      if ((tm = Getattr(p, "tmap:freearg"))) { +	Printv(cleanup, tm, "\n", NIL); +	p = Getattr(p, "tmap:freearg:next"); +      } else { +	p = nextSibling(p); +      } +    } + +    /* Insert argument output code */ +    String *outarg = NewString(""); +    for (p = l; p;) { +      if ((tm = Getattr(p, "tmap:argout"))) { +	//          // managing the number of returning variables +	//        if (numoutputs=Getattr(p,"tmap:argout:numoutputs")){ +	//                      int i=GetInt(p,"tmap:argout:numoutputs"); +	//                      printf("got argout:numoutputs of %d\n",i); +	//                      returnval+=GetInt(p,"tmap:argout:numoutputs"); +	//        } +	//        else returnval++; +	Replaceall(tm, "$arg", Getattr(p, "emit:input")); +	Replaceall(tm, "$input", Getattr(p, "emit:input")); +	Printv(outarg, tm, "\n", NIL); +	p = Getattr(p, "tmap:argout:next"); +      } else { +	p = nextSibling(p); +      } +    } + +    // Remember C name of the wrapping function +    Setattr(n, "wrap:name", wname); + +    /* Emit the function call */ +    String *actioncode = emit_action(n); + +    /* NEW LANGUAGE NOTE:*********************************************** +       FIXME: +       returns 1 if there is a void return type +       this is because there is a typemap for void +       NEW LANGUAGE NOTE:END *********************************************** */ +    // Return value if necessary +    if ((tm = Swig_typemap_lookup_out("out", n, Swig_cresult_name(), f, actioncode))) { +      // managing the number of returning variables +      //      if (numoutputs=Getattr(tm,"numoutputs")){ +      //              int i=GetInt(tm,"numoutputs"); +      //              printf("return numoutputs %d\n",i); +      //              returnval+=GetInt(tm,"numoutputs"); +      //      } +      //        else returnval++; +      if (GetFlag(n, "feature:new")) { +	Replaceall(tm, "$owner", "1"); +      } else { +	Replaceall(tm, "$owner", "0"); +      } +      Printf(f->code, "%s\n", tm); +      //      returnval++; +    } else { +      Swig_warning(WARN_TYPEMAP_OUT_UNDEF, input_file, line_number, "Unable to use return type %s in function %s.\n", SwigType_str(d, 0), name); +    } +    emit_return_variable(n, d, f); + +    /* Output argument output code */ +    Printv(f->code, outarg, NIL); + +    /* Output cleanup code */ +    Printv(f->code, cleanup, NIL); + +    /* Look to see if there is any newfree cleanup code */ +    if (GetFlag(n, "feature:new")) { +      if ((tm = Swig_typemap_lookup("newfree", n, Swig_cresult_name(), 0))) { +	Printf(f->code, "%s\n", tm); +      } +    } + +    /* See if there is any return cleanup code */ +    if ((tm = Swig_typemap_lookup("ret", n, Swig_cresult_name(), 0))) { +      Printf(f->code, "%s\n", tm); +    } + + +    /* Close the function */ +    Printv(f->code, "return SWIG_arg;\n", NIL); +    // add the failure cleanup code: +    Printv(f->code, "\nfail: SWIGUNUSED;\n", "$cleanup", NIL); +    if (CPlusPlus) Append(f->code, "}\n"); +    Printv(f->code, "lua_error(L);\n", NIL); +    // lua_error() calls longjmp() but we need a dummy return to avoid compiler +    // warnings. +    Printv(f->code, "return 0;\n", NIL); +    Printf(f->code, "}\n"); + +    /* Substitute the cleanup code */ +    Replaceall(f->code, "$cleanup", cleanup); + +    /* Substitute the function name */ +    Replaceall(f->code, "$symname", iname); +    Replaceall(f->code, "$result", Swig_cresult_name()); + +    /* Dump the function out */ +    /* in Lua we will not emit the destructor as a wrapper function, +       Lua will automatically call the destructor when the object is free'd +       However: you cannot just skip this function as it will not emit +       any custom destructor (using %extend), as you need to call emit_action() +       Therefore we go though the whole function,  +       but do not write the code into the wrapper +     */ +    if (!current[DESTRUCTOR]) { +      Wrapper_print(f, f_wrappers); +    } + +    /* NEW LANGUAGE NOTE:*********************************************** +       register the function in SWIG +       different language mappings seem to use different ideas +       NEW LANGUAGE NOTE:END *********************************************** */ +    /* Now register the function with the interpreter. */ +    int result = SWIG_OK; +    if (Getattr(n, "sym:overloaded")) { +      if (!Getattr(n, "sym:nextSibling")) { +	result = dispatchFunction(n); +      } +    } + +    Delete(argument_check); +    Delete(argument_parse); + +    Delete(cleanup); +    Delete(outarg); +    //    Delete(description); +    DelWrapper(f); + +    return result; +  } + +  /* ------------------------------------------------------------ +   * dispatchFunction() +   * +   * Emit overloading dispatch function +   * ------------------------------------------------------------ */ + +  /* NEW LANGUAGE NOTE:*********************************************** +     This is an extra function used for overloading of functions +     it checks the args & then calls the relevant fn +     most of the real work in again typemaps: +     look for %typecheck(SWIG_TYPECHECK_*) in the .swg file +     NEW LANGUAGE NOTE:END *********************************************** */ +  int dispatchFunction(Node *n) { +    //REPORT("dispatchFunction", n); +    /* Last node in overloaded chain */ + +    int maxargs; +    String *tmp = NewString(""); +    String *dispatch = Swig_overload_dispatch(n, "return %s(L);", &maxargs); + +    /* Generate a dispatch wrapper for all overloaded functions */ + +    Wrapper *f = NewWrapper(); +    String *symname = Getattr(n, "sym:name"); +    String *lua_name = Getattr(n, "lua:name"); +    assert(lua_name); +    String *wname = Swig_name_wrapper(symname); + +    //Printf(stdout,"Swig_overload_dispatch %s %s '%s' %d\n",symname,wname,dispatch,maxargs); + +    if (!luaAddSymbol(lua_name, n)) { +      DelWrapper(f); +      Delete(dispatch); +      Delete(tmp); +      return SWIG_ERROR; +    } + +    Printv(f->def, "static int ", wname, "(lua_State* L) {", NIL); +    Wrapper_add_local(f, "argc", "int argc"); +    Printf(tmp, "int argv[%d]={1", maxargs + 1); +    for (int i = 1; i <= maxargs; i++) { +      Printf(tmp, ",%d", i + 1); +    } +    Printf(tmp, "}"); +    Wrapper_add_local(f, "argv", tmp); +    Printf(f->code, "argc = lua_gettop(L);\n"); + +    Replaceall(dispatch, "$args", "self,args"); +    Printv(f->code, dispatch, "\n", NIL); + +    Node *sibl = n; +    while (Getattr(sibl, "sym:previousSibling")) +      sibl = Getattr(sibl, "sym:previousSibling");	// go all the way up +    String *protoTypes = NewString(""); +    do { +      String *fulldecl = Swig_name_decl(sibl); +      Printf(protoTypes, "\n\"    %s\\n\"", fulldecl); +      Delete(fulldecl); +    } while ((sibl = Getattr(sibl, "sym:nextSibling"))); +    Printf(f->code, "SWIG_Lua_pusherrstring(L,\"Wrong arguments for overloaded function '%s'\\n\"\n" +	   "\"  Possible C/C++ prototypes are:\\n\"%s);\n", symname, protoTypes); +    Delete(protoTypes); + +    Printf(f->code, "lua_error(L);return 0;\n"); +    Printv(f->code, "}\n", NIL); +    Wrapper_print(f, f_wrappers); + +    // Remember C name of the wrapping function +    Setattr(n, "wrap:name", wname); + +    if (current[CONSTRUCTOR]) { +      if (constructor_name != 0) +	Delete(constructor_name); +      constructor_name = Copy(wname); +    } + +    DelWrapper(f); +    Delete(dispatch); +    Delete(tmp); + +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * Add variable to "attributes"  C arrays of given namespace or class. +   * Input is node. Based on the state of "current" array it determines +   * the name of the getter function, setter function etc and calls +   * registerVariable overload with necessary params. +   * Lua scope could be overwritten. (Used only for backward compatibility) +   * ------------------------------------------------------------ */ + +  void registerVariable(Node *n, bool overwrite = false, String *overwriteLuaScope = 0) { +    int assignable = is_assignable(n); +    String *symname = Getattr(n, "sym:name"); +    assert(symname); + +    // Lua scope. It is not symbol NSpace, it is the actual key to retrieve getCArraysHash. +    String *luaScope = luaCurrentSymbolNSpace(); +    if (overwrite) +      luaScope = overwriteLuaScope; + +    // Getter and setter +    String *getName = 0; +    String *setName = 0; +    String *mrename = 0; +    if (current[NO_CPP] || !getCurrentClass()) { +      // Global variable +      getName = Swig_name_get(getNSpace(), symname); +      if (assignable) +        setName = Swig_name_set(getNSpace(), symname); +    } else { +        assert(!current[NO_CPP]); +        if (current[STATIC_VAR] ) { +          mrename = Swig_name_member(getNSpace(), getClassPrefix(), symname); +          getName = Swig_name_get(0, mrename); +          if (assignable) +            setName = Swig_name_set(0, mrename); +        } else if (current[MEMBER_VAR]) { +          mrename = Swig_name_member(0, getClassPrefix(), symname); +          getName = Swig_name_get(getNSpace(), mrename); +          if (assignable) +            setName = Swig_name_set(getNSpace(), mrename); +        } else { +          assert(false); +        } +    } + +    getName = Swig_name_wrapper(getName); +    if (setName) +      setName = Swig_name_wrapper(setName); +    registerVariable(luaScope, n, getName, setName); +  } + +  /* ------------------------------------------------------------ +   * registerVariable() +   * +   * Add variable to the "attributes" (or "get"/"set" in +   * case of elua_ltr) C arrays of given namespace or class +   * ------------------------------------------------------------ */ + +  void registerVariable(String *lua_nspace_or_class_name, Node *n, String *getName, String *setName) { +    String *unassignable = NewString("SWIG_Lua_set_immutable"); +    if (setName == 0 || GetFlag(n, "feature:immutable")) { +      setName = unassignable; +    } +    Hash *nspaceHash = getCArraysHash(lua_nspace_or_class_name); +    String *s_ns_methods_tab = Getattr(nspaceHash, "methods"); +    String *s_ns_var_tab = Getattr(nspaceHash, "attributes"); +    String *lua_name = Getattr(n, "lua:name"); +    if (elua_ltr) { +      String *s_ns_dot_get = Getattr(nspaceHash, "get"); +      String *s_ns_dot_set = Getattr(nspaceHash, "set"); +      Printf(s_ns_dot_get, "%s{LSTRKEY(\"%s\"), LFUNCVAL(%s)},\n", tab4, lua_name, getName); +      Printf(s_ns_dot_set, "%s{LSTRKEY(\"%s\"), LFUNCVAL(%s)},\n", tab4, lua_name, setName); +    } else if (eluac_ltr) { +      Printv(s_ns_methods_tab, tab4, "{LSTRKEY(\"", lua_name, "_get", "\")", ", LFUNCVAL(", getName, ")", "},\n", NIL); +      Printv(s_ns_methods_tab, tab4, "{LSTRKEY(\"", lua_name, "_set", "\")", ", LFUNCVAL(", setName, ")", "},\n", NIL); +    } else { +      Printf(s_ns_var_tab, "%s{ \"%s\", %s, %s },\n", tab4, lua_name, getName, setName); +    } +  } + +  /* ------------------------------------------------------------ +   * variableWrapper() +   * ------------------------------------------------------------ */ + +  virtual int variableWrapper(Node *n) { +    /* NEW LANGUAGE NOTE:*********************************************** +       Language::variableWrapper(n) will generate two wrapper fns +       Foo_get & Foo_set by calling functionWrapper() +       so we will just add these into the variable lists +       ideally we should not have registered these as functions, +       only WRT this variable will look into this later. +       NEW LANGUAGE NOTE:END *********************************************** */ +    //    REPORT("variableWrapper", n); +    String *lua_name = Getattr(n, "lua:name"); +    assert(lua_name); +    (void)lua_name; +    current[VARIABLE] = true; +    // let SWIG generate the wrappers +    int result = Language::variableWrapper(n); +     +    // It is impossible to use registerVariable, because sym:name of the Node is currently +    // in an undefined state - the callees of this function may have modified it. +    // registerVariable should be used from respective callees.* +    current[VARIABLE] = false; +    return result; +  } + + +  /* ------------------------------------------------------------ +   * Add constant to appropriate C array. constantRecord is an array record. +   * Actually, in current implementation it is resolved consttab typemap +   * ------------------------------------------------------------ */ + +  void registerConstant(String *nspace, String *constantRecord) { +    Hash *nspaceHash = getCArraysHash(nspace); +    String *s_const_tab = 0; +    if (eluac_ltr || elua_ltr) +      // In elua everything goes to "methods" tab +      s_const_tab = Getattr(nspaceHash, "methods"); +    else +      s_const_tab = Getattr(nspaceHash, "constants"); + +    assert(s_const_tab); +    Printf(s_const_tab, "    %s,\n", constantRecord); + +    if ((eluac_ltr || elua_ltr) && old_metatable_bindings) { +      s_const_tab = Getattr(nspaceHash, "constants"); +      assert(s_const_tab); +      Printf(s_const_tab, "    %s,\n", constantRecord); +    } + +  } + +  /* ------------------------------------------------------------ +   * constantWrapper() +   * ------------------------------------------------------------ */ + +  virtual int constantWrapper(Node *n) { +    REPORT("constantWrapper", n); +    String *name = Getattr(n, "name"); +    String *iname = Getattr(n, "sym:name"); +    String *lua_name = Getattr(n, "lua:name"); +    if (lua_name == 0) +      lua_name = iname; +    String *nsname = Copy(iname); +    SwigType *type = Getattr(n, "type"); +    String *rawval = Getattr(n, "rawval"); +    String *value = rawval ? rawval : Getattr(n, "value"); +    String *tm; +    String *lua_name_v2 = 0; +    String *tm_v2 = 0; +    String *iname_v2 = 0; +    Node *n_v2 = 0; + +    if (!luaAddSymbol(lua_name, n)) +      return SWIG_ERROR; + +    Swig_save("lua_constantMember", n, "sym:name", NIL); +    Setattr(n, "sym:name", lua_name); +    /* Special hook for member pointer */ +    if (SwigType_type(type) == T_MPOINTER) { +      String *wname = Swig_name_wrapper(iname); +      Printf(f_wrappers, "static %s = %s;\n", SwigType_str(type, wname), value); +      value = Char(wname); +    } + +    if ((tm = Swig_typemap_lookup("consttab", n, name, 0))) { +      Replaceall(tm, "$value", value); +      Replaceall(tm, "$nsname", nsname); +      registerConstant(luaCurrentSymbolNSpace(), tm); +    } else if ((tm = Swig_typemap_lookup("constcode", n, name, 0))) { +      Replaceall(tm, "$value", value); +      Replaceall(tm, "$nsname", nsname); +      Printf(f_init, "%s\n", tm); +    } else { +      Delete(nsname); +      nsname = 0; +      Swig_warning(WARN_TYPEMAP_CONST_UNDEF, input_file, line_number, "Unsupported constant value.\n"); +      Swig_restore(n); +      return SWIG_NOWRAP; +    } + +    bool make_v2_compatible = old_metatable_bindings && getCurrentClass() && old_compatible_names; + +    if (make_v2_compatible) { +      // Don't do anything for enums in C mode - they are already +      // wrapped correctly +      if (CPlusPlus || !current[ENUM_CONST]) { +	lua_name_v2 = Swig_name_member(0, proxy_class_name, lua_name); +	iname_v2 = Swig_name_member(0, proxy_class_name, iname); +        n_v2 = Copy(n); +        if (!luaAddSymbol(iname_v2, n, getNSpace())) { +          Swig_restore(n); +          return SWIG_ERROR; +        } + +        Setattr(n_v2, "sym:name", lua_name_v2); +        tm_v2 = Swig_typemap_lookup("consttab", n_v2, name, 0); +        if (tm_v2) { +          Replaceall(tm_v2, "$value", value); +          Replaceall(tm_v2, "$nsname", nsname); +          registerConstant(getNSpace(), tm_v2); +        } else { +          tm_v2 = Swig_typemap_lookup("constcode", n_v2, name, 0); +          if (!tm_v2) { +            // This can't be. +            assert(false); +            Swig_restore(n); +            return SWIG_ERROR; +          } +          Replaceall(tm_v2, "$value", value); +          Replaceall(tm_v2, "$nsname", nsname); +          Printf(f_init, "%s\n", tm_v2); +        } +        Delete(n_v2); +      } +    } + +    Swig_restore(n); +    Delete(nsname); +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * nativeWrapper() +   * ------------------------------------------------------------ */ + +  virtual int nativeWrapper(Node *n) { +    //    REPORT("nativeWrapper", n); +    String *symname = Getattr(n, "sym:name"); +    String *wrapname = Getattr(n, "wrap:name"); +    if (!luaAddSymbol(wrapname, n)) +      return SWIG_ERROR; + +    Hash *nspaceHash = getCArraysHash(getNSpace()); +    String *s_ns_methods_tab = Getattr(nspaceHash, "methods"); +    Printv(s_ns_methods_tab, tab4, "{ \"", symname, "\",", wrapname, "},\n", NIL); +    //   return Language::nativeWrapper(n); // this does nothing... +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * enumDeclaration() +   * ------------------------------------------------------------ */ + +  virtual int enumDeclaration(Node *n) { +    if (getCurrentClass() && (cplus_mode != PUBLIC)) +      return SWIG_NOWRAP; + +    current[STATIC_CONST] = true; +    current[ENUM_CONST] = true; +    // There is some slightly specific behaviour with enums. Basically, +    // their NSpace may be tracked separately. The code below tries to work around +    // this issue to some degree. +    // The idea is the same as in classHandler - to drop old names generation if +    // enum is in class in namespace. +    const int old_compatible_names_saved = old_compatible_names; +    if (getNSpace() || ( Getattr(n, "sym:nspace") != 0 && Len(Getattr(n, "sym:nspace")) > 0 ) ) { +      old_compatible_names = 0; +    } +    int result = Language::enumDeclaration(n); +    current[STATIC_CONST] = false; +    current[ENUM_CONST] = false; +    old_compatible_names = old_compatible_names_saved; +    return result; +  } + +  /* ------------------------------------------------------------ +   * enumvalueDeclaration() +   * ------------------------------------------------------------ */ + +  virtual int enumvalueDeclaration(Node *n) { +    if (getCurrentClass() && (cplus_mode != PUBLIC)) +      return SWIG_NOWRAP; + +    Swig_require("enumvalueDeclaration", n, "*name", "?value", "*sym:name", NIL); +    String *symname = Getattr(n, "sym:name"); +    String *value = Getattr(n, "value"); +    String *name = Getattr(n, "name"); +    String *tmpValue; +    Node *parent = parentNode(n); + +    if (value) +      tmpValue = NewString(value); +    else +      tmpValue = NewString(name); +    Setattr(n, "value", tmpValue); + +    Setattr(n, "name", tmpValue);	/* for wrapping of enums in a namespace when emit_action is used */ + +    if (GetFlag(parent, "scopedenum")) { +      symname = Swig_name_member(0, Getattr(parent, "sym:name"), symname); +      Setattr(n, "sym:name", symname); +      Delete(symname); +    } + +    int result = constantWrapper(n); + +    Delete(tmpValue); +    Swig_restore(n); +    return result; +  } + +  /* ------------------------------------------------------------ +   * classDeclaration() +   * ------------------------------------------------------------ */ + +  virtual int classDeclaration(Node *n) { +    return Language::classDeclaration(n); +  } + + +  /* ------------------------------------------------------------ +   * Helper function that adds record to appropriate C arrays +   * ------------------------------------------------------------ */ + +  void registerClass(String *scope, String *wrap_class) { +    assert(wrap_class); +    Hash *nspaceHash = getCArraysHash(scope); +    String *ns_classes = Getattr(nspaceHash, "classes"); +    Printv(ns_classes, "&", wrap_class, ",\n", NIL); +    if (elua_ltr || eluac_ltr) { +      String *ns_methods = Getattr(nspaceHash, "methods"); +      Hash *class_hash = getCArraysHash(class_static_nspace); +      assert(class_hash); +      String *cls_methods = Getattr(class_hash, "methods:name"); +      assert(cls_methods); +      Printv(ns_methods, tab4, "{LSTRKEY(\"", proxy_class_name, "\")", ", LROVAL(", cls_methods, ")", "},\n", NIL); +    } +  } + +  /* ------------------------------------------------------------ +   * classHandler() +   * ------------------------------------------------------------ */ + +  virtual int classHandler(Node *n) { +    //REPORT("classHandler", n); + +    String *mangled_full_proxy_class_name = 0; +    String *destructor_name = 0; +    String *nspace = getNSpace(); + +    constructor_name = 0; +    have_constructor = 0; +    have_destructor = 0; +    destructor_action = 0; +    assert(class_static_nspace == 0); +    assert(full_proxy_class_name == 0); +    assert(proxy_class_name == 0); + +    current[NO_CPP] = false; + +    proxy_class_name = Getattr(n, "sym:name"); +    // We have to enforce nspace here, because technically we are already +    // inside class parsing (getCurrentClass != 0), but we should register +    // class in its parent namespace +    if (!luaAddSymbol(proxy_class_name, n, nspace)) +      return SWIG_ERROR; + +    if (nspace == 0) +      full_proxy_class_name = NewStringf("%s", proxy_class_name); +    else +      full_proxy_class_name = NewStringf("%s.%s", nspace, proxy_class_name); + +    assert(full_proxy_class_name); +    mangled_full_proxy_class_name = Swig_name_mangle(full_proxy_class_name); + +    SwigType *t = Copy(Getattr(n, "name")); +    SwigType *fr_t = SwigType_typedef_resolve_all(t);	/* Create fully resolved type */ +    SwigType *t_tmp = 0; +    t_tmp = SwigType_typedef_qualified(fr_t);	// Temporal variable +    Delete(fr_t); +    fr_t = SwigType_strip_qualifiers(t_tmp); +    String *mangled_fr_t = 0; +    mangled_fr_t = SwigType_manglestr(fr_t); +    // not sure exactly how this works, +    // but tcl has a static hashtable of all classes emitted and then only emits code for them once. +    // this fixes issues in test suites: template_default2 & template_specialization + +    // * if i understand correctly, this is a bug. +    // * consider effect on template_specialization_defarg + +    static Hash *emitted = NewHash(); +    if (GetFlag(emitted, mangled_fr_t)) { +      full_proxy_class_name = 0; +      proxy_class_name = 0; +      return SWIG_NOWRAP; +    } +    SetFlag(emitted, mangled_fr_t); + +    // We treat class T as both 'class' and 'namespace'. All static members, attributes +    // and constants are considered part of namespace T, all members - part of the 'class' +    // Now, here is a trick. Static methods, attributes and non-static methods and attributes +    // are described with same structures - swig_lua_attribute/swig_lua_method. Instead of calling +    // getCArraysHash(class name) to initialize things for static methods/attributes and then +    // manually doing same initialization for non-static methods, we call getCArraysHash 2 times: +    // 1) With name "class name" + "." + "SwigStatic" to initialize static things +    // 2) With "class name" to initialize non-static things +    Hash *instance_cls = getCArraysHash(full_proxy_class_name, false); +    assert(instance_cls); +    String *s_attr_tab_name = Getattr(instance_cls, "attributes:name"); +    String *s_methods_tab_name = Getattr(instance_cls, "methods:name"); +    SetFlag(instance_cls, "lua:no_namespaces"); +    SetFlag(instance_cls, "lua:no_classes"); +    SetFlag(instance_cls, "lua:class_instance"); + +    /* There is no use for "constants", "classes" and "namespaces" arrays. +     * All constants are considered part of static part of class. +     */ + +    class_static_nspace = NewStringf("%s%sSwigStatic", full_proxy_class_name, NSPACE_SEPARATOR); +    Hash *static_cls = getCArraysHash(class_static_nspace, false); +    assert(static_cls); +    SetFlag(static_cls, "lua:no_namespaces"); +    SetFlag(static_cls, "lua:class_static"); + +    // Notifying instance_cls and static_cls hashes about each other +    Setattr(instance_cls, "lua:class_instance:static_hash", static_cls); +    Setattr(static_cls, "lua:class_static:instance_hash", instance_cls); + +    const int old_compatible_names_saved = old_compatible_names; +    // If class has %nspace enabled, then generation of backward compatible names +    // should be disabled +    if (getNSpace()) { +      old_compatible_names = 0; +    } + +    /* There is no use for "classes" and "namespaces" arrays. Subclasses are not supported +     * by SWIG and namespaces couldn't be nested inside classes (C++ Standard) +     */ +    // Generate normal wrappers +    Language::classHandler(n); + +    old_compatible_names = old_compatible_names_saved; + +    SwigType_add_pointer(t); + +    // Catch all: eg. a class with only static functions and/or variables will not have 'remembered' +    String *wrap_class_name = Swig_name_wrapper(NewStringf("class_%s", mangled_full_proxy_class_name)); +    String *wrap_class = NewStringf("&%s", wrap_class_name); +    SwigType_remember_clientdata(t, wrap_class); + +    String *rt = Copy(getClassType()); +    SwigType_add_pointer(rt); + +    // Adding class to appropriate namespace +    registerClass(nspace, wrap_class_name); +    Hash *nspaceHash = getCArraysHash(nspace); + +    // Register the class structure with the type checker +    //    Printf(f_init,"SWIG_TypeClientData(SWIGTYPE%s, (void *) &_wrap_class_%s);\n", SwigType_manglestr(t), mangled_full_proxy_class_name); + +    // emit a function to be called to delete the object  +    if (have_destructor) { +      destructor_name = NewStringf("swig_delete_%s", mangled_full_proxy_class_name); +      Printv(f_wrappers, "static void ", destructor_name, "(void *obj) {\n", NIL); +      if (destructor_action) { +	Printv(f_wrappers, SwigType_str(rt, "arg1"), " = (", SwigType_str(rt, 0), ") obj;\n", NIL); +	Printv(f_wrappers, destructor_action, "\n", NIL); +      } else { +	if (CPlusPlus) { +	  Printv(f_wrappers, "    delete (", SwigType_str(rt, 0), ") obj;\n", NIL); +	} else { +	  Printv(f_wrappers, "    free((char *) obj);\n", NIL); +	} +      } +      Printf(f_wrappers, "}\n"); +    } +    // Wrap constructor wrapper into one more proxy function. It will be used as class namespace __call method, thus +    // allowing both +    // Module.ClassName.StaticMethod to access static method/variable/constant +    // Module.ClassName() to create new object +    if (have_constructor) { +      assert(constructor_name); +      String *constructor_proxy_name = NewStringf("_proxy_%s", constructor_name); +      Printv(f_wrappers, "static int ", constructor_proxy_name, "(lua_State *L) {\n", NIL); +      Printv(f_wrappers, +	     tab4, "assert(lua_istable(L,1));\n", +	     tab4, "lua_pushcfunction(L,", constructor_name, ");\n", +	     tab4, "assert(!lua_isnil(L,-1));\n", +	     tab4, "lua_replace(L,1); /* replace our table with real constructor */\n", +	     tab4, "lua_call(L,lua_gettop(L)-1,1);\n", +	     tab4, "return 1;\n}\n", NIL); +      Delete(constructor_name); +      constructor_name = constructor_proxy_name; +      if (elua_ltr) { +	String *static_cls_metatable_tab = Getattr(static_cls, "metatable"); +	assert(static_cls_metatable_tab); +	Printf(static_cls_metatable_tab, "    {LSTRKEY(\"__call\"), LFUNCVAL(%s)},\n", constructor_name); +      } else if (eluac_ltr) { +	String *ns_methods_tab = Getattr(nspaceHash, "methods"); +	assert(ns_methods_tab); +	Printv(ns_methods_tab, tab4, "{LSTRKEY(\"", "new_", proxy_class_name, "\")", ", LFUNCVAL(", constructor_name, ")", "},\n", NIL); +      } +    } +    if (have_destructor) { +      if (eluac_ltr) { +	String *ns_methods_tab = Getattr(nspaceHash, "methods"); +	assert(ns_methods_tab); +	Printv(ns_methods_tab, tab4, "{LSTRKEY(\"", "free_", mangled_full_proxy_class_name, "\")", ", LFUNCVAL(", destructor_name, ")", "},\n", NIL); +      } +    } + +    closeCArraysHash(full_proxy_class_name, f_wrappers); +    closeCArraysHash(class_static_nspace, f_wrappers); + + +    // Handle inheritance +    // note: with the idea of class hierarchies spread over multiple modules +    // cf test-suite: imports.i +    // it is not possible to just add the pointers to the base classes to the code +    // (as sometimes these classes are not present) +    // therefore we instead hold the name of the base class and a null pointer +    // at runtime: we can query the swig type manager & see if the class exists +    // if so, we can get the pointer to the base class & replace the null pointer +    // if the type does not exist, then we cannot... +    String *base_class = NewString(""); +    String *base_class_names = NewString(""); + +    List *baselist = Getattr(n, "bases"); +    if (baselist && Len(baselist)) { +      Iterator b; +      b = First(baselist); +      while (b.item) { +	String *bname = Getattr(b.item, "name"); +	if ((!bname) || GetFlag(b.item, "feature:ignore") || (!Getattr(b.item, "module"))) { +	  b = Next(b); +	  continue; +	} +	// stores a null pointer & the name +	Printf(base_class, "0,"); +	Printf(base_class_names, "\"%s *\",", SwigType_namestr(bname)); + +	b = Next(b); +      } +    } +    // First, print class static part +    printCArraysDefinition(class_static_nspace, proxy_class_name, f_wrappers); + +    assert(mangled_full_proxy_class_name); +    assert(base_class); +    assert(base_class_names); +    assert(proxy_class_name); +    assert(full_proxy_class_name); +     +    // Then print class instance part +    Printv(f_wrappers, "static swig_lua_class *swig_", mangled_full_proxy_class_name, "_bases[] = {", base_class, "0};\n", NIL); +    Delete(base_class); +    Printv(f_wrappers, "static const char *swig_", mangled_full_proxy_class_name, "_base_names[] = {", base_class_names, "0};\n", NIL); +    Delete(base_class_names); + +    Printv(f_wrappers, "static swig_lua_class _wrap_class_", mangled_full_proxy_class_name, " = { \"", proxy_class_name, "\", \"", full_proxy_class_name, "\", &SWIGTYPE", +	   SwigType_manglestr(t), ",", NIL); + +    if (have_constructor) { +      Printv(f_wrappers, constructor_name, NIL); +      Delete(constructor_name); +      constructor_name = 0; +    } else { +      Printf(f_wrappers, "0"); +    } + +    if (have_destructor) { +      Printv(f_wrappers, ", ", destructor_name, NIL); +    } else { +      Printf(f_wrappers, ",0"); +    } +    Printf(f_wrappers, ", %s, %s, &%s", s_methods_tab_name, s_attr_tab_name, Getattr(static_cls, "cname")); +     +    if (!eluac_ltr) { +      Printf(f_wrappers, ", %s", Getattr(instance_cls,"metatable:name")); +    } +    else +      Printf(f_wrappers, ", 0"); + +    Printf(f_wrappers, ", swig_%s_bases, swig_%s_base_names };\n\n", mangled_full_proxy_class_name, mangled_full_proxy_class_name); + +    current[NO_CPP] = true; +    Delete(class_static_nspace); +    class_static_nspace = 0; +    Delete(mangled_full_proxy_class_name); +    mangled_full_proxy_class_name = 0; +    Delete(destructor_name); +    destructor_name = 0; +    Delete(full_proxy_class_name); +    full_proxy_class_name = 0; +    proxy_class_name = 0; +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * memberfunctionHandler() +   * ------------------------------------------------------------ */ + +  virtual int memberfunctionHandler(Node *n) { +    String *symname = GetChar(n, "sym:name"); +    //Printf(stdout,"memberfunctionHandler %s %s\n",name,iname); + +    // Special case unary minus: LUA passes two parameters for the +    // wrapper function while we want only one. Tell our +    // functionWrapper to ignore a parameter. + +    if (Cmp(symname, "__unm") == 0) { +      //Printf(stdout, "unary minus: ignore one argument\n"); +      SetInt(n, "lua:ignore_args", 1); +    } + +    current[MEMBER_FUNC] = true; +    Language::memberfunctionHandler(n); + +    registerMethod(n); +    current[MEMBER_FUNC] = false; +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * membervariableHandler() +   * ------------------------------------------------------------ */ + +  virtual int membervariableHandler(Node *n) { +    //    REPORT("membervariableHandler",n); +    current[MEMBER_VAR] = true; +    Language::membervariableHandler(n); +    registerVariable(n); +    current[MEMBER_VAR] = false; +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * constructorHandler() +   * +   * Method for adding C++ member constructor +   * ------------------------------------------------------------ */ + +  virtual int constructorHandler(Node *n) { +    //    REPORT("constructorHandler", n); +    current[CONSTRUCTOR] = true; +    Language::constructorHandler(n); +    current[CONSTRUCTOR] = false; +    //constructor_name = NewString(Getattr(n, "sym:name")); +    have_constructor = 1; +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * destructorHandler() +   * ------------------------------------------------------------ */ + +  virtual int destructorHandler(Node *n) { +    REPORT("destructorHandler", n); +    current[DESTRUCTOR] = true; +    Language::destructorHandler(n); +    current[DESTRUCTOR] = false; +    have_destructor = 1; +    destructor_action = Getattr(n, "wrap:action"); +    return SWIG_OK; +  } + +  /* ---------------------------------------------------------------------- +   * globalfunctionHandler() +   * +   * It can be called: +   * 1. Usual C/C++ global function. +   * 2. During class parsing for functions declared/defined as friend +   * 3. During class parsing from staticmemberfunctionHandler +   * ---------------------------------------------------------------------- */ + +  virtual int globalfunctionHandler(Node *n) { +    bool oldVal = current[NO_CPP]; +    if (!current[STATIC_FUNC])	// If static function, don't switch to NO_CPP +      current[NO_CPP] = true; +    const int result = Language::globalfunctionHandler(n); +     +    if (!current[STATIC_FUNC]) // Register only if not called from static function handler +      registerMethod(n); +    current[NO_CPP] = oldVal; +    return result; +  } + +  /* ---------------------------------------------------------------------- +   * globalvariableHandler() +   * +   * Sets "current" array correctly +   * ---------------------------------------------------------------------- */ + +  virtual int globalvariableHandler(Node *n) { +    bool oldVal = current[NO_CPP]; +    current[GLOBAL_VAR] = true; +    current[NO_CPP] = true; + +    const int result = Language::globalvariableHandler(n); +    registerVariable(n); + +    current[GLOBAL_VAR] = false; +    current[NO_CPP] = oldVal; +    return result; +  } + + +  /* ----------------------------------------------------------------------- +   * staticmemberfunctionHandler() +   * +   * Wrap a static C++ function +   * ---------------------------------------------------------------------- */ + +  virtual int staticmemberfunctionHandler(Node *n) { +    REPORT("staticmemberfunctionHandler", n); +    current[STATIC_FUNC] = true; + +    const int result = Language::staticmemberfunctionHandler(n); +    registerMethod(n); + +    if (old_metatable_bindings && result == SWIG_OK && old_compatible_names) { +      Swig_require("lua_staticmemberfunctionHandler", n, "*lua:name", NIL); +      String *lua_name = Getattr(n, "lua:name"); +      // Although this function uses Swig_name_member, it actually generates the Lua name, +      // not the C++ name. This is because an earlier version used such a scheme for static function +      // name generation and we have to maintain backward compatibility. +      String *compat_name = Swig_name_member(0, proxy_class_name, lua_name); +      Setattr(n, "lua:name", compat_name); +      registerMethod(n, true, getNSpace()); +      Delete(compat_name); +      Swig_restore(n); +    } + +    current[STATIC_FUNC] = false;; +    return result; +  } + +  /* ------------------------------------------------------------ +   * memberconstantHandler() +   * +   * Create a C++ constant +   * ------------------------------------------------------------ */ + +  virtual int memberconstantHandler(Node *n) { +    REPORT("memberconstantHandler", n); +    int result = Language::memberconstantHandler(n); + +    return result; +  } + +  /* --------------------------------------------------------------------- +   * staticmembervariableHandler() +   * --------------------------------------------------------------------- */ + +  virtual int staticmembervariableHandler(Node *n) { +    REPORT("staticmembervariableHandler", n); +    current[STATIC_VAR] = true; +    //String *symname = Getattr(n, "sym:name"); +    int result = Language::staticmembervariableHandler(n); +    if (!GetFlag(n, "wrappedasconstant")) { +      registerVariable(n); +    } + +    if (result == SWIG_OK) { +      // This will add static member variable to the class namespace with name ClassName_VarName +      if (old_metatable_bindings && old_compatible_names) { +	Swig_save("lua_staticmembervariableHandler", n, "lua:name", NIL); +	String *lua_name = Getattr(n, "lua:name"); +	// Although this function uses Swig_name_member, it actually generates the Lua name, +	// not the C++ name. This is because an earlier version used such a scheme for static function +	// name generation and we have to maintain backward compatibility. +	String *v2_name = Swig_name_member(NIL, proxy_class_name, lua_name); +	if (!GetFlag(n, "wrappedasconstant")) { +	  Setattr(n, "lua:name", v2_name); +          // Registering static var in the class parent nspace +	  registerVariable(n, true, getNSpace()); +	} +	// If static member variable was wrapped as a constant, then +	// constant wrapper has already performed all actions necessary for old_metatable_bindings +	Delete(v2_name); +	Swig_restore(n); +      } +    } +    current[STATIC_VAR] = false; + +    return result; +  } + + +  /* --------------------------------------------------------------------- +   * external runtime generation +   * --------------------------------------------------------------------- */ + +  /* This is to support the usage +     SWIG -external-runtime <filename> +     The code consists of two functions: +     String *runtimeCode()  // returns a large string with all the runtimes in +     String *defaultExternalRuntimeFilename() // returns the default filename +     I am writing a generic solution, even though SWIG-Lua only has one file right now... +   */ +  String *runtimeCode() { +    String *s = NewString(""); +    const char *filenames[] = { "luarun.swg", 0 };	// must be 0 terminated + +    emitLuaFlavor(s); + +    String *sfile = 0; +    for (int i = 0; filenames[i] != 0; i++) { +      sfile = Swig_include_sys(filenames[i]); +      if (!sfile) { +	Printf(stderr, "*** Unable to open '%s'\n", filenames[i]); +      } else { +	Append(s, sfile); +	Delete(sfile); +      } +    } + +    return s; +  } + +  String *defaultExternalRuntimeFilename() { +    return NewString("swigluarun.h"); +  } + +  /* --------------------------------------------------------------------- +   * helpers +   * --------------------------------------------------------------------- */ + +  void emitLuaFlavor(String *s) { +    if (elua_emulate) { +      Printf(s, "/*This is only emulation!*/\n"); +      Printf(s, "#define SWIG_LUA_TARGET SWIG_LUA_FLAVOR_ELUA\n"); +      Printf(s, "#define SWIG_LUA_ELUA_EMULATE\n"); +    } else if (elua_ltr) +      Printf(s, "#define SWIG_LUA_TARGET SWIG_LUA_FLAVOR_ELUA\n"); +    else if (eluac_ltr) +      Printf(s, "#define SWIG_LUA_TARGET SWIG_LUA_FLAVOR_ELUAC\n"); +    else +      Printf(s, "#define SWIG_LUA_TARGET SWIG_LUA_FLAVOR_LUA\n"); +  } + + +  /* ----------------------------------------------------------------------------- +   * escapeCode() +   * +   * This is to convert the string of Lua code into a proper string, which can then be +   * emitted into the C/C++ code. +   * Basically it is a lot of search & replacing of odd sequences +   * ---------------------------------------------------------------------------- */ + +  void escapeCode(String *str) { +    //Printf(f_runtime,"/* original luacode:[[[\n%s\n]]]\n*/\n",str); +    Chop(str);			// trim +    Replace(str, "\\", "\\\\", DOH_REPLACE_ANY);	// \ to \\ (this must be done first) +    Replace(str, "\"", "\\\"", DOH_REPLACE_ANY);	// " to \" +    Replace(str, "\n", "\\n\"\n  \"", DOH_REPLACE_ANY);	// \n to \n"\n" (ie quoting every line) +    //Printf(f_runtime,"/* hacked luacode:[[[\n%s\n]]]\n*/\n",str); +  } + +  /* ----------------------------------------------------------------------------- +   * rawGetCArraysHash(String *name) +   * +   * A small helper to hide implementation of how CArrays hashes are stored +   * ---------------------------------------------------------------------------- */ + +  Hash *rawGetCArraysHash(const_String_or_char_ptr name) { +    Hash *scope = symbolScopeLookup( name ? name : "" ); +    if(!scope) +      return 0; + +    Hash *carrays_hash = Getattr(scope, "lua:cdata"); +    return carrays_hash; +  } +    +  /* ----------------------------------------------------------------------------- +   * getCArraysHash() +   * +   * Each namespace can be described with a hash that stores C arrays +   * where members of the namespace should be added. All these hashes are stored +   * inside the symbols table, in pseudo-symbol for every namespace. +   * nspace could be NULL (NSPACE_TODO), that means functions and variables and classes +   * that are not in any namespace (this is default for SWIG unless %nspace feature is used). +   * You can later set some attributes that will affect behaviour of functions that use this hash: +   * "lua:no_namespaces" will disable "namespaces" array. +   * "lua:no_classes" will disable "classes" array. +   * For every component ("attributes", "methods", etc) there are subcomponents: +   *   XXX:name - name of the C array that stores data for component +   *   XXX:decl - statement with forward declaration of this array; +   * Namespace could be automatically registered to its parent if 'reg' == true. This can only be +   * done during the first call (a.k.a when nspace is created). +   * ---------------------------------------------------------------------------- */ + +  Hash *getCArraysHash(String *nspace, bool reg = true) { +    Hash *scope = symbolScopeLookup(nspace ? nspace : ""); +    if(!scope) { +      symbolAddScope( nspace ? nspace : "" ); +      scope = symbolScopeLookup(nspace ? nspace : ""); +      assert(scope); +    } +    Hash *carrays_hash = Getattr(scope, "lua:cdata"); +    if (carrays_hash != 0) +      return carrays_hash; +    carrays_hash = NewHash(); +    String *mangled_name = 0; +    if (nspace == 0 || Len(nspace) == 0) +      mangled_name = NewString("SwigModule"); +    else +      mangled_name = Swig_name_mangle(nspace); +    String *cname = NewStringf("swig_%s", mangled_name); + +    Setattr(carrays_hash, "cname", cname); + +    String *attr_tab = NewString(""); +    String *attr_tab_name = NewStringf("swig_%s_attributes", mangled_name); +    String *attr_tab_decl = NewString(""); +    Printv(attr_tab, "static swig_lua_attribute ", NIL); +    Printv(attr_tab, attr_tab_name, "[]", NIL); +    Printv(attr_tab_decl, attr_tab, ";\n", NIL); +    Printv(attr_tab, " = {\n", NIL); +    Setattr(carrays_hash, "attributes", attr_tab); +    Setattr(carrays_hash, "attributes:name", attr_tab_name); +    Setattr(carrays_hash, "attributes:decl", attr_tab_decl); + +    String *methods_tab = NewString(""); +    String *methods_tab_name = NewStringf("swig_%s_methods", mangled_name); +    String *methods_tab_decl = NewString(""); +    if (elua_ltr || eluac_ltr)	// In this case methods array also acts as namespace rotable +      Printf(methods_tab, "const LUA_REG_TYPE "); +    else +      Printf(methods_tab, "static swig_lua_method "); +    Printv(methods_tab, methods_tab_name, "[]", NIL); +    Printv(methods_tab_decl, methods_tab, ";\n", NIL); +    Printv(methods_tab, "= {\n", NIL); +    Setattr(carrays_hash, "methods", methods_tab); +    Setattr(carrays_hash, "methods:name", methods_tab_name); +    Setattr(carrays_hash, "methods:decl", methods_tab_decl); + +    String *const_tab = NewString(""); +    String *const_tab_name = NewStringf("swig_%s_constants", mangled_name); +    String *const_tab_decl = NewString(""); +    if (elua_ltr || eluac_ltr)	// In this case const array holds rotable with namespace constants +      Printf(const_tab, "const LUA_REG_TYPE "); +    else +      Printf(const_tab, "static swig_lua_const_info "); +    Printv(const_tab, const_tab_name, "[]", NIL); +    Printv(const_tab_decl, const_tab, ";", NIL); +    Printv(const_tab, "= {\n", NIL); +    Setattr(carrays_hash, "constants", const_tab); +    Setattr(carrays_hash, "constants:name", const_tab_name); +    Setattr(carrays_hash, "constants:decl", const_tab_decl); + +    String *classes_tab = NewString(""); +    String *classes_tab_name = NewStringf("swig_%s_classes", mangled_name); +    String *classes_tab_decl = NewString(""); +    Printf(classes_tab, "static swig_lua_class* "); +    Printv(classes_tab, classes_tab_name, "[]", NIL); +    Printv(classes_tab_decl, classes_tab, ";", NIL); +    Printv(classes_tab, "= {\n", NIL); +    Setattr(carrays_hash, "classes", classes_tab); +    Setattr(carrays_hash, "classes:name", classes_tab_name); +    Setattr(carrays_hash, "classes:decl", classes_tab_decl); + +    String *namespaces_tab = NewString(""); +    String *namespaces_tab_name = NewStringf("swig_%s_namespaces", mangled_name); +    String *namespaces_tab_decl = NewString(""); +    Printf(namespaces_tab, "static swig_lua_namespace* "); +    Printv(namespaces_tab, namespaces_tab_name, "[]", NIL); +    Printv(namespaces_tab_decl, namespaces_tab, ";", NIL); +    Printv(namespaces_tab, " = {\n", NIL); +    Setattr(carrays_hash, "namespaces", namespaces_tab); +    Setattr(carrays_hash, "namespaces:name", namespaces_tab_name); +    Setattr(carrays_hash, "namespaces:decl", namespaces_tab_decl); + +    if (elua_ltr) { +      String *get_tab = NewString(""); +      String *get_tab_name = NewStringf("swig_%s_get", mangled_name); +      String *get_tab_decl = NewString(""); +      Printv(get_tab, "const LUA_REG_TYPE ", get_tab_name, "[]", NIL); +      Printv(get_tab_decl, get_tab, ";", NIL); +      Printv(get_tab, " = {\n", NIL); +      Setattr(carrays_hash, "get", get_tab); +      Setattr(carrays_hash, "get:name", get_tab_name); +      Setattr(carrays_hash, "get:decl", get_tab_decl); + +      String *set_tab = NewString(""); +      String *set_tab_name = NewStringf("swig_%s_set", mangled_name); +      String *set_tab_decl = NewString(""); +      Printv(set_tab, "const LUA_REG_TYPE ", set_tab_name, "[]", NIL); +      Printv(set_tab_decl, set_tab, ";", NIL); +      Printv(set_tab, " = {\n", NIL); +      Setattr(carrays_hash, "set", set_tab); +      Setattr(carrays_hash, "set:name", set_tab_name); +      Setattr(carrays_hash, "set:decl", set_tab_decl); + +    } +    if (!eluac_ltr) { +      String *metatable_tab = NewString(""); +      String *metatable_tab_name = NewStringf("swig_%s_meta", mangled_name); +      String *metatable_tab_decl = NewString(""); +      if (elua_ltr) // In this case const array holds rotable with namespace constants +	Printf(metatable_tab, "const LUA_REG_TYPE "); +      else +	Printf(metatable_tab, "static swig_lua_method "); +      Printv(metatable_tab, metatable_tab_name, "[]", NIL); +      Printv(metatable_tab_decl, metatable_tab, ";", NIL); +      Printv(metatable_tab, " = {\n", NIL); +      Setattr(carrays_hash, "metatable", metatable_tab); +      Setattr(carrays_hash, "metatable:name", metatable_tab_name); +      Setattr(carrays_hash, "metatable:decl", metatable_tab_decl); +    } + +    Setattr(scope, "lua:cdata", carrays_hash); +    assert(rawGetCArraysHash(nspace)); + +    if (reg && nspace != 0 && Len(nspace) != 0 && GetFlag(carrays_hash, "lua:no_reg") == 0) { +      // Split names into components +      List *components = Split(nspace, '.', -1); +      String *parent_path = NewString(""); +      int len = Len(components); +      String *name = Copy(Getitem(components, len - 1)); +      for (int i = 0; i < len - 1; i++) { +	if (i > 0) +	  Printv(parent_path, NSPACE_SEPARATOR, NIL); +	String *item = Getitem(components, i); +	Printv(parent_path, item, NIL); +      } +      Hash *parent = getCArraysHash(parent_path, true); +      String *namespaces_tab = Getattr(parent, "namespaces"); +      Printv(namespaces_tab, "&", cname, ",\n", NIL); +      if (elua_ltr || eluac_ltr) { +	String *methods_tab = Getattr(parent, "methods"); +	Printv(methods_tab, tab4, "{LSTRKEY(\"", name, "\")", ", LROVAL(", methods_tab_name, ")", "},\n", NIL); +      } +      Setattr(carrays_hash, "name", name); + +      Delete(components); +      Delete(parent_path); +    } else if (!reg)		// This namespace shouldn't be registered. Lets remember it. +      SetFlag(carrays_hash, "lua:no_reg"); + +    Delete(mangled_name); +    mangled_name = 0; +    return carrays_hash; +  } + +  /* ----------------------------------------------------------------------------- +   * closeCArraysHash() +   * +   * Functions add end markers {0,0,...,0} to all arrays, prints them to +   * output and marks hash as closed (lua:closed). Consequent attempts to +   * close the same hash will result in an error. +   * closeCArraysHash DOES NOT print structure that describes namespace, it only +   * prints array. You can use printCArraysDefinition to print structure. +   * if "lua:no_namespaces" is set, then array for "namespaces" won't be printed +   * if "lua:no_classes" is set, then array for "classes" won't be printed +   * ----------------------------------------------------------------------------- */ + +  void closeCArraysHash(String *nspace, File *output) { +    Hash *carrays_hash = rawGetCArraysHash(nspace); +    assert(carrays_hash); +    assert(GetFlag(carrays_hash, "lua:closed") == 0); + +    SetFlag(carrays_hash, "lua:closed"); + +    // Do arrays describe class instance part or class static part +    const int is_instance = GetFlag(carrays_hash, "lua:class_instance"); + + +    String *attr_tab = Getattr(carrays_hash, "attributes"); +    Printf(attr_tab, "    {0,0,0}\n};\n"); +    Printv(output, attr_tab, NIL); + +    String *const_tab = Getattr(carrays_hash, "constants"); +    String *const_tab_name = Getattr(carrays_hash, "constants:name"); +    if (elua_ltr || eluac_ltr) +      Printv(const_tab, tab4, "{LNILKEY, LNILVAL}\n", "};\n", NIL); +    else +      Printf(const_tab, "    {0,0,0,0,0,0}\n};\n"); +     +    // For the sake of compiling with -Wall -Werror we print constants +    // only when necessary +    int need_constants = 0; +    if ( (elua_ltr || eluac_ltr) && (old_metatable_bindings) ) +      need_constants = 1; +    else if (!is_instance) // static part need constants tab +      need_constants = 1; + +    if (need_constants) +      Printv(output, const_tab, NIL); + +    if (elua_ltr) { +      // Put forward declaration of metatable array +      Printv(output, "extern ", Getattr(carrays_hash, "metatable:decl"), "\n", NIL); +    } +    String *methods_tab = Getattr(carrays_hash, "methods"); +    String *metatable_tab_name = Getattr(carrays_hash, "metatable:name"); +    if (elua_ltr || eluac_ltr) { +      if (old_metatable_bindings) +	Printv(methods_tab, tab4, "{LSTRKEY(\"const\"), LROVAL(", const_tab_name, ")},\n", NIL); +      if (elua_ltr) { +	Printv(methods_tab, tab4, "{LSTRKEY(\"__metatable\"), LROVAL(", metatable_tab_name, ")},\n", NIL); +      } + +      Printv(methods_tab, tab4, "{LSTRKEY(\"__disown\"), LFUNCVAL(SWIG_Lua_class_disown)},\n", NIL); +      Printv(methods_tab, tab4, "{LNILKEY, LNILVAL}\n};\n", NIL); +    } else +      Printf(methods_tab, "    {0,0}\n};\n"); +    Printv(output, methods_tab, NIL); + +    if (!GetFlag(carrays_hash, "lua:no_classes")) { +      String *classes_tab = Getattr(carrays_hash, "classes"); +      Printf(classes_tab, "    0\n};\n"); +      Printv(output, classes_tab, NIL); +    } + +    if (!GetFlag(carrays_hash, "lua:no_namespaces")) { +      String *namespaces_tab = Getattr(carrays_hash, "namespaces"); +      Printf(namespaces_tab, "    0\n};\n"); +      Printv(output, namespaces_tab, NIL); +    } +    if (elua_ltr) { +      String *get_tab = Getattr(carrays_hash, "get"); +      String *set_tab = Getattr(carrays_hash, "set"); +      Printv(get_tab, tab4, "{LNILKEY, LNILVAL}\n};\n", NIL); +      Printv(set_tab, tab4, "{LNILKEY, LNILVAL}\n};\n", NIL); +      Printv(output, get_tab, NIL); +      Printv(output, set_tab, NIL); +    } + +    // Heuristic whether we need to print metatable or not. +    // For the sake of compiling with -Wall -Werror we don't print +    // metatable for static part. +    int need_metatable = 0; +    if (eluac_ltr) +      need_metatable = 0; +    else if(!is_instance) +      need_metatable = 0; +    else +      need_metatable = 1; + +    if (need_metatable) { +      String *metatable_tab = Getattr(carrays_hash, "metatable"); +      assert(metatable_tab); +      if (elua_ltr) { +	String *get_tab_name = Getattr(carrays_hash, "get:name"); +	String *set_tab_name = Getattr(carrays_hash, "set:name"); + +	if (GetFlag(carrays_hash, "lua:class_instance")) { +	  Printv(metatable_tab, tab4, "{LSTRKEY(\"__index\"), LFUNCVAL(SWIG_Lua_class_get)},\n", NIL); +	  Printv(metatable_tab, tab4, "{LSTRKEY(\"__newindex\"), LFUNCVAL(SWIG_Lua_class_set)},\n", NIL); +	} else { +	  Printv(metatable_tab, tab4, "{LSTRKEY(\"__index\"), LFUNCVAL(SWIG_Lua_namespace_get)},\n", NIL); +	  Printv(metatable_tab, tab4, "{LSTRKEY(\"__newindex\"), LFUNCVAL(SWIG_Lua_namespace_set)},\n", NIL); +	} + +	Printv(metatable_tab, tab4, "{LSTRKEY(\"__gc\"), LFUNCVAL(SWIG_Lua_class_destruct)},\n", NIL); +	Printv(metatable_tab, tab4, "{LSTRKEY(\".get\"), LROVAL(", get_tab_name, ")},\n", NIL); +	Printv(metatable_tab, tab4, "{LSTRKEY(\".set\"), LROVAL(", set_tab_name, ")},\n", NIL); +	Printv(metatable_tab, tab4, "{LSTRKEY(\".fn\"), LROVAL(", Getattr(carrays_hash, "methods:name"), ")},\n", NIL); + +	if (GetFlag(carrays_hash, "lua:class_instance")) { +	  String *static_cls = Getattr(carrays_hash, "lua:class_instance:static_hash"); +	  assert(static_cls); +	  // static_cls is swig_lua_namespace. This structure can't be used with eLua(LTR) +	  // Instead a structure describing its methods is used +	  String *static_cls_cname = Getattr(static_cls, "methods:name"); +	  assert(static_cls_cname); +	  Printv(metatable_tab, tab4, "{LSTRKEY(\".static\"), LROVAL(", static_cls_cname, ")},\n", NIL); +	  // Put forward declaration of this array +	  Printv(output, "extern ", Getattr(static_cls, "methods:decl"), "\n", NIL); +	} else if (GetFlag(carrays_hash, "lua:class_static")) { +	  Hash *instance_cls = Getattr(carrays_hash, "lua:class_static:instance_hash"); +	  assert(instance_cls); +	  String *instance_cls_metatable_name = Getattr(instance_cls, "metatable:name"); +	  assert(instance_cls_metatable_name); +	  Printv(metatable_tab, tab4, "{LSTRKEY(\".instance\"), LROVAL(", instance_cls_metatable_name, ")},\n", NIL); +	} + +	Printv(metatable_tab, tab4, "{LNILKEY, LNILVAL}\n};\n", NIL); +      } else { +	Printf(metatable_tab, "    {0,0}\n};\n"); +      } + +      Printv(output, metatable_tab, NIL); +    } + +    Printv(output, "\n", NIL); +  } + +  /* ----------------------------------------------------------------------------- +   * closeNamespaces() +   * +   * Recursively close all non-closed namespaces. Prints data to dataOutput. +   * ----------------------------------------------------------------------------- */ + +  void closeNamespaces(File *dataOutput) { +    // Special handling for empty module. +    if (symbolScopeLookup("") == 0 || rawGetCArraysHash("") == 0) { +      // Module is empty. Create hash for global scope in order to have swig_SwigModule +      // variable in resulting file +      getCArraysHash(0); +    } +    // Because we can't directly access 'symtabs', instead we access +    // top-level scope and look on all scope pseudo-symbols in it. +    Hash *top_scope = symbolScopeLookup(""); +    assert(top_scope); +    Iterator ki = First(top_scope); +    List *to_close = NewList(); +    while (ki.key) { +      assert(ki.item); +      if (Getattr(ki.item, "sym:scope")) { +        // We have a pseudo symbol. Lets get actual scope for this pseudo symbol +        Hash *carrays_hash = rawGetCArraysHash(ki.key); +        assert(carrays_hash); +        if (GetFlag(carrays_hash, "lua:closed") == 0) +          Append(to_close, ki.key); +      } +      ki = Next(ki); +    } +    SortList(to_close, &compareByLen); +    int len = Len(to_close); +    for (int i = 0; i < len; i++) { +      String *key = Getitem(to_close, i); +      closeCArraysHash(key, dataOutput); +      Hash *carrays_hash = rawGetCArraysHash(key); +      String *name = 0;		// name - name of the namespace as it should be visible in Lua +      if (DohLen(key) == 0)	// This is global module +	name = module; +      else +	name = Getattr(carrays_hash, "name"); +      assert(name); +      printCArraysDefinition(key, name, dataOutput); +    } +    Delete(to_close); +  } + +  /* ----------------------------------------------------------------------------- +   * printCArraysDefinition() +   * +   * This function prints to output a definition of namespace in form +   *   swig_lua_namespace $cname =  { attr_array, methods_array, ... , namespaces_array }; +   * You can call this function as many times as is necessary. +   * 'name' is a user-visible name that this namespace will have in Lua. It shouldn't +   * be a fully qualified name, just its own name. +   * ----------------------------------------------------------------------------- */ + +  void printCArraysDefinition(String *nspace, String *name, File *output) { +    Hash *carrays_hash = getCArraysHash(nspace, false); + +    String *cname = Getattr(carrays_hash, "cname");	// cname - name of the C structure that describes namespace +    assert(cname); +    Printv(output, "static swig_lua_namespace ", cname, " = ", NIL); + +    String *null_string = NewString("0"); +    String *attr_tab_name = Getattr(carrays_hash, "attributes:name"); +    String *methods_tab_name = Getattr(carrays_hash, "methods:name"); +    String *const_tab_name = Getattr(carrays_hash, "constants:name"); +    String *classes_tab_name = Getattr(carrays_hash, "classes:name"); +    String *namespaces_tab_name = Getattr(carrays_hash, "namespaces:name"); +    bool has_classes = GetFlag(carrays_hash, "lua:no_classes") == 0; +    bool has_namespaces = GetFlag(carrays_hash, "lua:no_namespaces") == 0; + +    Printv(output, "{\n", +	   tab4, "\"", name, "\",\n", +	   tab4, methods_tab_name, ",\n", +	   tab4, attr_tab_name, ",\n", +	   tab4, const_tab_name, ",\n", +	   tab4, (has_classes) ? classes_tab_name : null_string, ",\n", +	   tab4, (has_namespaces) ? namespaces_tab_name : null_string, "\n};\n", NIL); +    Delete(null_string); +  } + +  /* ----------------------------------------------------------------------------- +   * luaCurrentSymbolNSpace() +   * +   * This function determines actual namespace/scope where any symbol at the +   * current moment should be placed. It looks at the 'current' array +   * and depending on where are we - static class member/function, +   * instance class member/function or just global functions decides +   * where symbol should be put. +   * The namespace/scope doesn't depend from symbol, only from 'current' +   * ----------------------------------------------------------------------------- */ + +  String *luaCurrentSymbolNSpace() { +    String *scope = 0; +    // If outside class, than NSpace is used. +    // If inside class, but current[NO_CPP], then this is friend function. It belongs to NSpace +    if (!getCurrentClass() || current[NO_CPP]) { +      scope = getNSpace(); +    } else if (current[ENUM_CONST] && !CPlusPlus ) { +        // Enums in C mode go to NSpace +        scope = getNSpace(); +    } else { +      // If inside class, then either class static namespace or class fully qualified name is used +      assert(!current[NO_CPP]); +      if (current[STATIC_FUNC] || current[STATIC_VAR] || current[STATIC_CONST]) { +	scope = class_static_nspace; +      } else if (current[MEMBER_VAR] || current[CONSTRUCTOR] || current[DESTRUCTOR] +		 || current[MEMBER_FUNC]) { +	scope = full_proxy_class_name; +      } else {			// Friend functions are handled this way +	scope = class_static_nspace; +      } +      assert(scope); +    } +    return scope; +  } + +  /* ----------------------------------------------------------------------------- +   * luaAddSymbol() +   * +   * Our implementation of addSymbol. Determines scope correctly, then  +   * forwards to Language::addSymbol +   * ----------------------------------------------------------------------------- */ + +  int luaAddSymbol(const String *s, const Node *n) { +    String *scope = luaCurrentSymbolNSpace(); +    return luaAddSymbol(s, n, scope); +  } + +  /* ----------------------------------------------------------------------------- +   * luaAddSymbol() +   * +   * Overload. Enforces given scope. Actually, it simply forwards call to Language::addSymbol +   * ----------------------------------------------------------------------------- */ + +  int luaAddSymbol(const String *s, const Node *n, const_String_or_char_ptr scope) { +    int result = Language::addSymbol(s, n, scope); +    if (!result) +      Printf(stderr, "addSymbol(%s to scope %s) failed\n", s, scope); +    return result; +  } + +}; + +/* ----------------------------------------------------------------------------- + * swig_lua()    - Instantiate module + * ----------------------------------------------------------------------------- */ + +extern "C" Language *swig_lua(void) { +  return new LUA(); +} diff --git a/contrib/tools/swig/Source/Modules/main.cxx b/contrib/tools/swig/Source/Modules/main.cxx new file mode 100644 index 00000000000..f5bdec644c0 --- /dev/null +++ b/contrib/tools/swig/Source/Modules/main.cxx @@ -0,0 +1,1407 @@ +/* ----------------------------------------------------------------------------- + * This file is part of SWIG, which is licensed as a whole under version 3  + * (or any later version) of the GNU General Public License. Some additional + * terms also apply to certain portions of SWIG. The full details of the SWIG + * license and copyrights can be found in the LICENSE and COPYRIGHT files + * included with the SWIG source code as distributed by the SWIG developers + * and at https://www.swig.org/legal.html. + * + * main.cxx + * + * Main entry point to the SWIG core. + * ----------------------------------------------------------------------------- */ + +#include "swigconfig.h" + +#if defined(_WIN32) +#define WIN32_LEAN_AND_MEAN +#include <windows.h> +#endif + +#include "swigmod.h" + +#include "swigwarn.h" +#include "cparse.h" +#include <ctype.h> +#include <errno.h> +#include <limits.h>		// for INT_MAX + +// Global variables + +static Language *lang = 0;	// Language method +int CPlusPlus = 0; +int Extend = 0;			// Extend flag +int ForceExtern = 0;		// Force extern mode +int GenerateDefault = 1;	// Generate default constructors +int Verbose = 0; +int AddExtern = 0; +int NoExcept = 0; +int SwigRuntime = 0;		// 0 = no option, 1 = -runtime, 2 = -noruntime +extern "C" { +  int UseWrapperSuffix = 0;	// If 1, append suffix to non-overloaded functions too. +} + +/* Suppress warning messages for private inheritance, etc by default. +   These are enabled by command line option -Wextra. + +   WARN_PARSE_PRIVATE_INHERIT                   309 +   WARN_PARSE_BUILTIN_NAME                      321 +   WARN_PARSE_REDUNDANT                         322 +   WARN_TYPE_ABSTRACT                           403 +   WARN_TYPE_RVALUE_REF_QUALIFIER_IGNORED       405 +   WARN_LANG_OVERLOAD_CONST                     512 + */ +#define EXTRA_WARNINGS "309,403,405,512,321,322" + +extern "C" { +  extern String *ModuleName; +  extern int ignore_nested_classes; +  extern int kwargs_supported; +} + +/* usage string split into multiple parts otherwise string is too big for some compilers */ +/* naming conventions for commandline options - no underscores, no capital letters, join words together + * except when using a common prefix, then use '-' to separate, eg the debug-xxx options */ +static const char *usage1 = (const char *) "\ +\nGeneral Options\n\ +     -addextern      - Add extra extern declarations\n\ +     -c++            - Enable C++ processing\n\ +     -co <file>      - Check <file> out of the SWIG library\n\ +     -copyctor       - Automatically generate copy constructors wherever possible\n\ +     -cpperraswarn   - Treat the preprocessor #error statement as #warning (default)\n\ +     -cppext <ext>   - Change file extension of generated C++ files to <ext>\n\ +                       (default is cxx)\n\ +     -copyright      - Display copyright notices\n\ +     -debug-classes  - Display information about the classes found in the interface\n\ +     -debug-module <n>- Display module parse tree at stages 1-4, <n> is a csv list of stages\n\ +     -debug-symtabs  - Display symbol tables information\n\ +     -debug-symbols  - Display target language symbols in the symbol tables\n\ +     -debug-csymbols - Display C symbols in the symbol tables\n\ +     -debug-lsymbols - Display target language layer symbols\n\ +     -debug-quiet    - Display less parse tree node debug info when using other -debug options\n\ +     -debug-tags     - Display information about the tags found in the interface\n\ +     -debug-template - Display information for debugging templates\n\ +     -debug-top <n>  - Display entire parse tree at stages 1-4, <n> is a csv list of stages\n\ +     -debug-typedef  - Display information about the types and typedefs in the interface\n\ +     -debug-typemap  - Display typemap debugging information\n\ +     -debug-tmsearch - Display typemap search debugging information\n\ +     -debug-tmused   - Display typemaps used debugging information\n\ +     -directors      - Turn on director mode for all the classes, mainly for testing\n\ +     -dirprot        - Turn on wrapping of protected members for director classes (default)\n\ +     -D<symbol>      - Define a symbol <symbol> (for conditional compilation)\n\ +"; + +static const char *usage2 = (const char *) "\ +     -E              - Preprocess only, does not generate wrapper code\n\ +     -external-runtime [file] - Export the SWIG runtime stack\n\ +     -fakeversion <v>- Make SWIG fake the program version number to <v>\n\ +     -fcompact       - Compile in compact mode\n\ +     -features <list>- Set global features, where <list> is a comma separated list of\n\ +                       features, eg -features directors,autodoc=1\n\ +                       If no explicit value is given to the feature, a default of 1 is used\n\ +     -fastdispatch   - Enable fast dispatch mode to produce faster overload dispatcher code\n\ +     -Fmicrosoft     - Display error/warning messages in Microsoft format\n\ +     -Fstandard      - Display error/warning messages in commonly used format\n\ +     -fvirtual       - Compile in virtual elimination mode\n\ +     -help           - Display help\n\ +     -I-             - Don't search the current directory\n\ +     -I<dir>         - Look for SWIG files in directory <dir>\n\ +     -ignoremissing  - Ignore missing include files\n\ +     -importall      - Follow all #include statements as imports\n\ +     -includeall     - Follow all #include statements\n\ +     -l<ifile>       - Include SWIG library file <ifile>\n\ +"; + +static const char *usage3 = (const char *) "\ +     -macroerrors    - Report errors inside macros\n\ +     -makedefault    - Create default constructors/destructors (the default)\n\ +     -M              - List all dependencies\n\ +     -MD             - Is equivalent to `-M -MF <file>', except `-E' is not implied\n\ +     -MF <file>      - Generate dependencies into <file> and continue generating wrappers\n\ +     -MM             - List dependencies, but omit files in SWIG library\n\ +     -MMD            - Like `-MD', but omit files in SWIG library\n\ +     -module <name>  - Set module name to <name>\n\ +     -MP             - Generate phony targets for all dependencies\n\ +     -MT <target>    - Set the target of the rule emitted by dependency generation\n\ +     -nocontract     - Turn off contract checking\n\ +     -nocpperraswarn - Do not treat the preprocessor #error statement as #warning\n\ +     -nodefault      - Do not generate default constructors nor default destructors\n\ +     -nodefaultctor  - Do not generate implicit default constructors\n\ +     -nodefaultdtor  - Do not generate implicit default destructors\n\ +     -nodirprot      - Do not wrap director protected members\n\ +     -noexcept       - Do not wrap exception specifiers\n\ +     -nofastdispatch - Disable fast dispatch mode (default)\n\ +     -nopreprocess   - Skip the preprocessor step\n\ +     -notemplatereduce - Disable reduction of the typedefs in templates\n\ +"; + +static const char *usage4 = (const char *) "\ +     -O              - Enable the optimization options:\n\ +                        -fastdispatch -fvirtual\n\ +     -o <outfile>    - Set name of C/C++ output file to <outfile>\n\ +     -oh <headfile>  - Set name of C++ output header file for directors to <headfile>\n\ +     -outcurrentdir  - Set default output dir to current dir instead of input file's path\n\ +     -outdir <dir>   - Set language specific files output directory to <dir>\n\ +     -pcreversion    - Display PCRE2 version information\n\ +     -small          - Compile in virtual elimination and compact mode\n\ +     -swiglib        - Report location of SWIG library and exit\n\ +     -templatereduce - Reduce all the typedefs in templates\n\ +     -v              - Run in verbose mode\n\ +     -version        - Display SWIG version number\n\ +     -Wall           - Remove all warning suppression, also implies -Wextra\n\ +     -Wallkw         - Enable keyword warnings for all the supported languages\n\ +     -Werror         - Treat warnings as errors\n\ +     -Wextra         - Adds the following additional warnings: " EXTRA_WARNINGS "\n\ +     -w<list>        - Suppress/add warning messages, eg -w401,+321 - see Warnings.html\n\ +     -xmlout <file>  - Write XML version of the parse tree to <file> after normal processing\n\ +\n\ +Options can also be defined using the SWIG_FEATURES environment variable, for example:\n\ +\n\ +  $ SWIG_FEATURES=\"-Wall\"\n\ +  $ export SWIG_FEATURES\n\ +  $ swig -python interface.i\n\ +\n\ +is equivalent to:\n\ +\n\ +  $ swig -Wall -python interface.i\n\ +\n\ +Arguments may also be passed in a file, separated by whitespace. For example:\n\ +\n\ +  $ echo \"-Wall -python interface.i\" > args.txt\n\ +  $ swig @args.txt\n\ +\n"; + +// Local variables +static String *LangSubDir = 0; // Target language library subdirectory +static String *SwigLib = 0; // Library directory +static String *SwigLibWinUnix = 0; // Extra library directory on Windows +static int freeze = 0; +static String *lang_config = 0; +static const char *hpp_extension = "h"; +static const char *cpp_extension = "cxx"; +static const char *depends_extension = "d"; +static String *outdir = 0; +static String *xmlout = 0; +static int outcurrentdir = 0; +static int help = 0; +static int checkout = 0; +static int cpp_only = 0; +static int no_cpp = 0; +static String *outfile_name = 0; +static String *outfile_name_h = 0; +static int tm_debug = 0; +static int dump_symtabs = 0; +static int dump_symbols = 0; +static int dump_csymbols = 0; +static int dump_lang_symbols = 0; +static int dump_tags = 0; +static int dump_module = 0; +static int dump_top = 0; +static int dump_xml = 0; +static int dump_typedef = 0; +static int dump_classes = 0; +static int werror = 0; +static int depend = 0; +static int depend_only = 0; +static int depend_phony = 0; +static int memory_debug = 0; +static int allkw = 0; +static DOH *cpps = 0; +static String *dependencies_file = 0; +static String *dependencies_target = 0; +static int external_runtime = 0; +static String *external_runtime_name = 0; +enum { STAGE1=1, STAGE2=2, STAGE3=4, STAGE4=8, STAGEOVERFLOW=16 }; +static List *libfiles = 0; +static List *all_output_files = 0; + +/* ----------------------------------------------------------------------------- + * check_extension() + * + * Checks the extension of a file to see if we should emit extern declarations. + * ----------------------------------------------------------------------------- */ + +static bool check_extension(String *filename) { +  bool wanted = false; +  const char *name = Char(filename); +  if (!name) +    return 0; +  String *extension = Swig_file_extension(name); +  const char *c = Char(extension); +  if ((strcmp(c, ".c") == 0) || +      (strcmp(c, ".C") == 0) || (strcmp(c, ".cc") == 0) || (strcmp(c, ".cxx") == 0) || (strcmp(c, ".c++") == 0) || (strcmp(c, ".cpp") == 0)) { +    wanted = true; +  } +  Delete(extension); +  return wanted; +} + +/* ----------------------------------------------------------------------------- + * install_opts() + * + * Install all command line options as preprocessor symbols + * ----------------------------------------------------------------------------- */ + +static void install_opts(int argc, char *argv[]) { +  int i; +  int noopt = 0; +  char *c; +  for (i = 1; i < (argc - 1); i++) { +    if (argv[i]) { +      if ((*argv[i] == '-') && (!isupper(*(argv[i] + 1)))) { +	String *opt = NewStringf("SWIGOPT%(upper)s", argv[i]); +	Replaceall(opt, "-", "_"); +	c = Char(opt); +	noopt = 0; +	while (*c) { +	  if (!(isalnum(*c) || (*c == '_'))) { +	    noopt = 1; +	    break; +	  } +	  c++; +	} +	if (((i + 1) < (argc - 1)) && (argv[i + 1]) && (*argv[i + 1] != '-')) { +	  Printf(opt, " %s", argv[i + 1]); +	  i++; +	} else { +	  Printf(opt, " 1"); +	} +	if (!noopt) { +	  /*      Printf(stdout,"%s\n", opt); */ +	  Preprocessor_define(opt, 0); +	} +	Delete(opt); +      } +    } +  } +} + +/* ----------------------------------------------------------------------------- + * decode_numbers_list() + * + * Decode comma separated list into a binary number of the inputs or'd together + * eg list="1,4" will return (2^0 || 2^3) = 0x1001 + * ----------------------------------------------------------------------------- */ + +static unsigned int decode_numbers_list(String *numlist) { +  unsigned int decoded_number = 0; +  if (numlist) { +    List *numbers = Split(numlist, ',', INT_MAX); +    if (numbers && Len(numbers) > 0) { +      for (Iterator it = First(numbers); it.item; it = Next(it)) { +        String *numstring = it.item; +        // TODO: check that it is a number +        int number = atoi(Char(numstring)); +        if (number > 0 && number <= 16) { +          decoded_number |= (1 << (number-1)); +        } +      } +    } +  } +  return decoded_number; +} + +/* ----------------------------------------------------------------------------- + * Sets the output directory for language specific (proxy) files from the + * C wrapper file if not set and corrects the directory name and adds a trailing + * file separator if necessary. + * ----------------------------------------------------------------------------- */ + +static void configure_outdir(const String *c_wrapper_outfile) { + +  // Use the C wrapper file's directory if the output directory has not been set by user +  if (!outdir || Len(outdir) == 0) +    outdir = Swig_file_dirname(c_wrapper_outfile); + +  Swig_filename_correct(outdir); + +  // Add trailing file delimiter if not present in output directory name +  if (Len(outdir) > 0) { +    const char *outd = Char(outdir); +    if (strcmp(outd + strlen(outd) - strlen(SWIG_FILE_DELIMITER), SWIG_FILE_DELIMITER) != 0) +      Printv(outdir, SWIG_FILE_DELIMITER, NIL); +  } +} + +/* This function sets the name of the configuration file */ +void SWIG_config_file(const_String_or_char_ptr filename) { +  lang_config = NewString(filename); +} + +/* Sets the target language subdirectory name */ +void SWIG_library_directory(const char *subdirectory) { +  LangSubDir = NewString(subdirectory); +} + +// Returns the directory for generating language specific files (non C/C++ files) +const String *SWIG_output_directory() { +  assert(outdir); +  return outdir; +} + +void SWIG_config_cppext(const char *ext) { +  cpp_extension = ext; +} + +List *SWIG_output_files() { +  assert(all_output_files); +  return all_output_files; +} + +void SWIG_setfeature(const char *cfeature, const char *cvalue) { +  Hash *features_hash = Swig_cparse_features(); +  String *name = NewString(""); +  String *fname = NewString(cfeature); +  String *fvalue = NewString(cvalue); +  Swig_feature_set(features_hash, name, 0, fname, fvalue, 0); +  Delete(name); +  Delete(fname); +  Delete(fvalue); +} + + +void SWIG_setfeatures(const char *c) { +  char feature[64]; +  char *fb = feature; +  char *fe = fb + 63; +  Hash *features_hash = Swig_cparse_features(); +  String *name = NewString(""); +  /* Printf(stderr,"all features %s\n", c); */ +  while (*c) { +    char *f = fb; +    String *fname = NewString("feature:"); +    String *fvalue = NewString(""); +    while ((f != fe) && *c != '=' && *c != ',' && *c) { +      *(f++) = *(c++); +    } +    *f = 0; +    Printf(fname, "%s", feature); +    if (*c && *(c++) == '=') { +      char value[64]; +      char *v = value; +      char *ve = v + 63; +      while ((v != ve) && *c != ',' && *c && !isspace(*c)) { +	*(v++) = *(c++); +      } +      *v = 0; +      Printf(fvalue, "%s", value); +    } else { +      Printf(fvalue, "1"); +    } +    /* Printf(stderr,"%s %s\n", fname, fvalue);  */ +    Swig_feature_set(features_hash, name, 0, fname, fvalue, 0); +    Delete(fname); +    Delete(fvalue); +  } +  Delete(name); +} + +/* This function handles the -external-runtime command option */ +static void SWIG_dump_runtime() { +  String *outfile; +  File *runtime; +  String *s; + +  outfile = external_runtime_name; +  if (!outfile) { +    outfile = lang->defaultExternalRuntimeFilename(); +    if (!outfile) { +      Printf(stderr, "*** Please provide a filename for the external runtime\n"); +      Exit(EXIT_FAILURE); +    } +  } + +  runtime = NewFile(outfile, "w", SWIG_output_files()); +  if (!runtime) { +    FileErrorDisplay(outfile); +    Exit(EXIT_FAILURE); +  } + +  Swig_banner(runtime); +  Printf(runtime, "\n"); + +  s = Swig_include_sys("swiglabels.swg"); +  if (!s) { +    Printf(stderr, "*** Unable to open 'swiglabels.swg'\n"); +    Delete(runtime); +    Exit(EXIT_FAILURE); +  } +  Printf(runtime, "%s", s); +  Delete(s); + +  s = Swig_include_sys("swigerrors.swg"); +  if (!s) { +    Printf(stderr, "*** Unable to open 'swigerrors.swg'\n"); +    Delete(runtime); +    Exit(EXIT_FAILURE); +  } +  Printf(runtime, "%s", s); +  Delete(s); + +  s = Swig_include_sys("swigrun.swg"); +  if (!s) { +    Printf(stderr, "*** Unable to open 'swigrun.swg'\n"); +    Delete(runtime); +    Exit(EXIT_FAILURE); +  } +  Printf(runtime, "%s", s); +  Delete(s); + +  s = lang->runtimeCode(); +  Printf(runtime, "%s", s); +  Delete(s); + +  s = Swig_include_sys("runtime.swg"); +  if (!s) { +    Printf(stderr, "*** Unable to open 'runtime.swg'\n"); +    Delete(runtime); +    Exit(EXIT_FAILURE); +  } +  Printf(runtime, "%s", s); +  Delete(s); + +  Delete(runtime); +  Exit(EXIT_SUCCESS); +} + +static void getoptions(int argc, char *argv[]) { +  int i; +  // Get options +  for (i = 1; i < argc; i++) { +    if (argv[i] && !Swig_check_marked(i)) { +      if (strncmp(argv[i], "-I-", 3) == 0) { +	// Don't push/pop directories +	Swig_set_push_dir(0); +	Swig_mark_arg(i); +      } else if (strncmp(argv[i], "-I", 2) == 0) { +	// Add a new directory search path +	Swig_add_directory((String_or_char*)(argv[i] + 2)); +	Swig_mark_arg(i); +      } else if (strncmp(argv[i], "-D", 2) == 0) { +	String *d = NewString(argv[i] + 2); +	if (Replace(d, "=", " ", DOH_REPLACE_FIRST) == 0) { +	  // Match C preprocessor behaviour whereby -DFOO sets FOO=1. +	  Append(d, " 1"); +	} +	Preprocessor_define((DOH *) d, 0); +	Delete(d); +	// Create a symbol +	Swig_mark_arg(i); +      } else if (strcmp(argv[i], "-E") == 0) { +	cpp_only = 1; +	Swig_mark_arg(i); +      } else if (strcmp(argv[i], "-nopreprocess") == 0) { +	no_cpp = 1; +	Swig_mark_arg(i); +      } else if ((strcmp(argv[i], "-verbose") == 0) || (strcmp(argv[i], "-v") == 0)) { +	Verbose = 1; +	Swig_mark_arg(i); +      } else if (strcmp(argv[i], "-c++") == 0) { +	CPlusPlus = 1; +	Preprocessor_define((DOH *) "__cplusplus __cplusplus", 0); +	Swig_cparse_cplusplus(1); +	Swig_mark_arg(i); +      } else if (strcmp(argv[i], "-c++out") == 0) { +	// Undocumented +	Swig_cparse_cplusplusout(1); +	Swig_mark_arg(i); +      } else if (strcmp(argv[i], "-fcompact") == 0) { +	Wrapper_compact_print_mode_set(1); +	Swig_mark_arg(i); +      } else if (strcmp(argv[i], "-fvirtual") == 0) { +	Wrapper_virtual_elimination_mode_set(1); +	Swig_mark_arg(i); +      } else if (strcmp(argv[i], "-fastdispatch") == 0) { +	Wrapper_fast_dispatch_mode_set(1); +	Swig_mark_arg(i); +      } else if (strcmp(argv[i], "-nofastdispatch") == 0) { +	Wrapper_fast_dispatch_mode_set(0); +	Swig_mark_arg(i); +      } else if (strcmp(argv[i], "-naturalvar") == 0) { +	Wrapper_naturalvar_mode_set(1); +	Swig_mark_arg(i); +      } else if (strcmp(argv[i], "-directors") == 0) { +	SWIG_setfeature("feature:director", "1"); +	Wrapper_director_mode_set(1); +	Swig_mark_arg(i); +      } else if (strcmp(argv[i], "-dirprot") == 0) { +	Wrapper_director_protected_mode_set(1); +	Swig_mark_arg(i); +      } else if (strcmp(argv[i], "-nodirprot") == 0) { +	Wrapper_director_protected_mode_set(0); +	Swig_mark_arg(i); +      } else if (strcmp(argv[i], "-pcreversion") == 0) { +	String *version = Swig_pcre_version(); +	Printf(stdout, "%s\n", version); +	Delete(version); +	Swig_mark_arg(i); +	Exit(EXIT_SUCCESS); +      } else if (strcmp(argv[i], "-small") == 0) { +	Wrapper_compact_print_mode_set(1); +	Wrapper_virtual_elimination_mode_set(1); +	Swig_mark_arg(i); +      } else if (strcmp(argv[i], "-runtime") == 0) { // Used to also accept -c. removed in swig-1.3.36 +	Swig_mark_arg(i); +	Swig_warning(WARN_DEPRECATED_OPTC, "SWIG", 1, "-runtime, -noruntime command line options are deprecated.\n"); +	SwigRuntime = 1; +      } else if (strcmp(argv[i], "-noruntime") == 0) { +	Swig_mark_arg(i); +	Swig_warning(WARN_DEPRECATED_OPTC, "SWIG", 1, "-runtime, -noruntime command line options are deprecated.\n"); +	SwigRuntime = 2; +      } else if (strcmp(argv[i], "-external-runtime") == 0) { +	external_runtime = 1; +	Swig_mark_arg(i); +	if (argv[i + 1]) { +	  external_runtime_name = NewString(argv[i + 1]); +	  Swig_mark_arg(i + 1); +	  i++; +	} +      } else if ((strcmp(argv[i], "-make_default") == 0) || (strcmp(argv[i], "-makedefault") == 0)) { +	GenerateDefault = 1; +	Swig_mark_arg(i); +      } else if ((strcmp(argv[i], "-no_default") == 0) || (strcmp(argv[i], "-nodefault") == 0)) { +	GenerateDefault = 0; +	Swig_warning(WARN_DEPRECATED_NODEFAULT, "SWIG", 1, "dangerous, use -nodefaultctor, -nodefaultdtor instead.\n"); +	Swig_mark_arg(i); +      } else if ((strcmp(argv[i], "-nodefaultctor") == 0)) { +	SWIG_setfeature("feature:nodefaultctor", "1"); +	Swig_mark_arg(i); +      } else if ((strcmp(argv[i], "-nodefaultdtor") == 0)) { +	SWIG_setfeature("feature:nodefaultdtor", "1"); +	Swig_mark_arg(i); +      } else if ((strcmp(argv[i], "-copyctor") == 0)) { +	SWIG_setfeature("feature:copyctor", "1"); +	Swig_mark_arg(i); +      } else if (strcmp(argv[i], "-noexcept") == 0) { +	NoExcept = 1; +	Swig_mark_arg(i); +      } else if (strcmp(argv[i], "-noextern") == 0) { +	Swig_warning(WARN_DEPRECATED_NOEXTERN, "SWIG", 1, "-noextern command line option is deprecated; extern is no longer generated by default.\n"); +	AddExtern = 0; +	Swig_mark_arg(i); +      } else if (strcmp(argv[i], "-addextern") == 0) { +	AddExtern = 1; +	Swig_mark_arg(i); +      } else if ((strcmp(argv[i], "-debug-template") == 0) || (strcmp(argv[i], "-debug_template") == 0) || (strcmp(argv[i], "-show_templates") == 0)) { +	Swig_cparse_debug_templates(1); +	Swig_mark_arg(i); +      } else if (strcmp(argv[i], "-templatereduce") == 0) { +	SWIG_cparse_template_reduce(1); +	Swig_mark_arg(i); +      } else if (strcmp(argv[i], "-notemplatereduce") == 0) { +	SWIG_cparse_template_reduce(0); +	Swig_mark_arg(i); +      } else if (strcmp(argv[i], "-macroerrors") == 0) { +	Swig_cparse_follow_locators(1); +	Swig_mark_arg(i); +      } else if (strcmp(argv[i], "-swiglib") == 0) { +	Printf(stdout, "%s\n", SwigLib); +	if (SwigLibWinUnix) +	  Printf(stdout, "%s\n", SwigLibWinUnix); +	Exit(EXIT_SUCCESS); +      } else if (strcmp(argv[i], "-o") == 0) { +	Swig_mark_arg(i); +	if (argv[i + 1]) { +	  outfile_name = NewString(argv[i + 1]); +          Swig_filename_correct(outfile_name); +	  if (!outfile_name_h || !dependencies_file) { +	    char *ext = strrchr(Char(outfile_name), '.'); +	    String *basename = ext ? NewStringWithSize(Char(outfile_name), (int)(Char(ext) - Char(outfile_name))) : NewString(outfile_name); +	    if (!dependencies_file) { +	      dependencies_file = NewStringf("%s.%s", basename, depends_extension); +	    } +	    if (!outfile_name_h) { +	      Printf(basename, ".%s", hpp_extension); +	      outfile_name_h = NewString(basename); +	    } +	    Delete(basename); +	  } +	  Swig_mark_arg(i + 1); +	  i++; +	} else { +	  Swig_arg_error(); +	} +      } else if (strcmp(argv[i], "-oh") == 0) { +	Swig_mark_arg(i); +	if (argv[i + 1]) { +	  outfile_name_h = NewString(argv[i + 1]); +          Swig_filename_correct(outfile_name_h); +	  Swig_mark_arg(i + 1); +	  i++; +	} else { +	  Swig_arg_error(); +	} +      } else if (strcmp(argv[i], "-fakeversion") == 0) { +	Swig_mark_arg(i); +	if (argv[i + 1]) { +	  Swig_set_fakeversion(argv[i + 1]); +	  Swig_mark_arg(i + 1); +	  i++; +	} else { +	  Swig_arg_error(); +	} +      } else if (strcmp(argv[i], "-version") == 0) { +	fprintf(stdout, "\nSWIG Version %s\n", Swig_package_version()); +	fprintf(stdout, "\nCompiled with %s [%s]\n", SWIG_CXX, SWIG_PLATFORM); +	fprintf(stdout, "\nConfigured options: %cpcre\n", +#ifdef HAVE_PCRE +		'+' +#else +		'-' +#endif +	    ); +	fprintf(stdout, "\nPlease see %s for reporting bugs and further information\n", PACKAGE_BUGREPORT); +	Exit(EXIT_SUCCESS); +      } else if (strcmp(argv[i], "-copyright") == 0) { +	fprintf(stdout, "\nSWIG Version %s\n", Swig_package_version()); +	fprintf(stdout, "Copyright (c) 1995-1998\n"); +	fprintf(stdout, "University of Utah and the Regents of the University of California\n"); +	fprintf(stdout, "Copyright (c) 1998-2005\n"); +	fprintf(stdout, "University of Chicago\n"); +	fprintf(stdout, "Copyright (c) 2005-2006\n"); +	fprintf(stdout, "Arizona Board of Regents (University of Arizona)\n"); +	Exit(EXIT_SUCCESS); +      } else if (strncmp(argv[i], "-l", 2) == 0) { +	// Add a new directory search path +	Append(libfiles, argv[i] + 2); +	Swig_mark_arg(i); +      } else if (strcmp(argv[i], "-co") == 0) { +	checkout = 1; +	Swig_mark_arg(i); +      } else if (strcmp(argv[i], "-features") == 0) { +	Swig_mark_arg(i); +	if (argv[i + 1]) { +	  SWIG_setfeatures(argv[i + 1]); +	  Swig_mark_arg(i + 1); +	} else { +	  Swig_arg_error(); +	} +      } else if (strcmp(argv[i], "-freeze") == 0) { +	freeze = 1; +	Swig_mark_arg(i); +      } else if (strcmp(argv[i], "-includeall") == 0) { +	Preprocessor_include_all(1); +	Swig_mark_arg(i); +      } else if (strcmp(argv[i], "-importall") == 0) { +	Preprocessor_import_all(1); +	Swig_mark_arg(i); +      } else if (strcmp(argv[i], "-ignoremissing") == 0) { +	Preprocessor_ignore_missing(1); +	Swig_mark_arg(i); +      } else if (strcmp(argv[i], "-cpperraswarn") == 0) { +	Preprocessor_error_as_warning(1); +	Swig_mark_arg(i); +      } else if (strcmp(argv[i], "-nocpperraswarn") == 0) { +	Preprocessor_error_as_warning(0); +	Swig_mark_arg(i); +      } else if (strcmp(argv[i], "-cppext") == 0) { +	Swig_mark_arg(i); +	if (argv[i + 1]) { +	  SWIG_config_cppext(argv[i + 1]); +	  Swig_mark_arg(i + 1); +	  i++; +	} else { +	  Swig_arg_error(); +	} +      } else if ((strcmp(argv[i], "-debug-typemap") == 0) || (strcmp(argv[i], "-debug_typemap") == 0) || (strcmp(argv[i], "-tm_debug") == 0)) { +	tm_debug = 1; +	Swig_mark_arg(i); +      } else if (strcmp(argv[i], "-debug-tmsearch") == 0) { +	Swig_typemap_search_debug_set(); +	Swig_mark_arg(i); +      } else if (strcmp(argv[i], "-debug-tmused") == 0) { +	Swig_typemap_used_debug_set(); +	Swig_mark_arg(i); +      } else if (strcmp(argv[i], "-module") == 0) { +	Swig_mark_arg(i); +	if (argv[i + 1]) { +	  ModuleName = NewString(argv[i + 1]); +	  Swig_mark_arg(i + 1); +	} else { +	  Swig_arg_error(); +	} +      } else if (strcmp(argv[i], "-M") == 0) { +	depend = 1; +	depend_only = 1; +	Swig_mark_arg(i); +      } else if (strcmp(argv[i], "-MM") == 0) { +	depend = 2; +	depend_only = 1; +	Swig_mark_arg(i); +      } else if (strcmp(argv[i], "-MF") == 0) { +	Swig_mark_arg(i); +	if (argv[i + 1]) { +	  dependencies_file = NewString(argv[i + 1]); +	  Swig_mark_arg(i + 1); +	} else { +	  Swig_arg_error(); +	} +      } else if (strcmp(argv[i], "-MD") == 0) { +	depend = 1; +	Swig_mark_arg(i); +      } else if (strcmp(argv[i], "-MMD") == 0) { +	depend = 2; +	Swig_mark_arg(i); +      } else if (strcmp(argv[i], "-MP") == 0) { +	depend_phony = 1; +	Swig_mark_arg(i); +      } else if (strcmp(argv[i], "-MT") == 0) { +	Swig_mark_arg(i); +	if (argv[i + 1]) { +          if (!dependencies_target) +            dependencies_target = NewString(argv[i + 1]); +          else +            Printf(dependencies_target, " %s", argv[i + 1]); +	  Swig_mark_arg(i + 1); +	} else { +	  Swig_arg_error(); +	} +      } else if (strcmp(argv[i], "-outdir") == 0) { +	Swig_mark_arg(i); +	if (argv[i + 1]) { +	  outdir = NewString(argv[i + 1]); +	  Swig_mark_arg(i + 1); +	} else { +	  Swig_arg_error(); +	} +      } else if (strcmp(argv[i], "-outcurrentdir") == 0) { +	Swig_mark_arg(i); +	outcurrentdir = 1; +      } else if (strcmp(argv[i], "-Wall") == 0) { +	Swig_mark_arg(i); +	Swig_warnall(); +      } else if (strcmp(argv[i], "-Wallkw") == 0) { +	allkw = 1; +	Swig_mark_arg(i); +      } else if (strcmp(argv[i], "-Werror") == 0) { +	werror = 1; +	Swig_mark_arg(i); +      } else if (strcmp(argv[i], "-Wextra") == 0) { +	Swig_mark_arg(i); +        Swig_warnfilter(EXTRA_WARNINGS, 0); +      } else if (strncmp(argv[i], "-w", 2) == 0) { +	Swig_mark_arg(i); +	Swig_warnfilter(argv[i] + 2, 1); +      } else if (strcmp(argv[i], "-debug-quiet") == 0) { +	Swig_print_quiet(1); +	Swig_mark_arg(i); +      } else if (strcmp(argv[i], "-debug-symtabs") == 0) { +	dump_symtabs = 1; +	Swig_mark_arg(i); +      } else if (strcmp(argv[i], "-debug-symbols") == 0) { +	dump_symbols = 1; +	Swig_mark_arg(i); +      } else if (strcmp(argv[i], "-debug-csymbols") == 0) { +	dump_csymbols = 1; +	Swig_mark_arg(i); +      } else if (strcmp(argv[i], "-debug-lsymbols") == 0) { +	dump_lang_symbols = 1; +	Swig_mark_arg(i); +      } else if ((strcmp(argv[i], "-debug-tags") == 0) || (strcmp(argv[i], "-dump_tags") == 0)) { +	dump_tags = 1; +	Swig_mark_arg(i); +      } else if (strcmp(argv[i], "-debug-top") == 0) { +	Swig_mark_arg(i); +	if (argv[i + 1]) { +	  String *dump_list = NewString(argv[i + 1]); +	  dump_top = decode_numbers_list(dump_list); +          if (dump_top < STAGE1 || dump_top >= STAGEOVERFLOW) +            Swig_arg_error(); +          else +            Swig_mark_arg(i + 1); +          Delete(dump_list); +	} else { +	  Swig_arg_error(); +	} +      } else if (strcmp(argv[i], "-debug-module") == 0) { +	Swig_mark_arg(i); +	if (argv[i + 1]) { +	  String *dump_list = NewString(argv[i + 1]); +	  dump_module = decode_numbers_list(dump_list); +          if (dump_module < STAGE1 || dump_module >= STAGEOVERFLOW) +            Swig_arg_error(); +          else +            Swig_mark_arg(i + 1); +          Delete(dump_list); +	} else { +	  Swig_arg_error(); +	} +      } else if ((strcmp(argv[i], "-dump_tree") == 0) || (strcmp(argv[i], "-dump_top") == 0)) { +	dump_top |= STAGE4; +	Swig_mark_arg(i); +      } else if (strcmp(argv[i], "-dump_module") == 0) { +	dump_module |= STAGE4; +	Swig_mark_arg(i); +      } else if (strcmp(argv[i], "-dump_parse_module") == 0) { +	dump_module |= STAGE1; +	Swig_mark_arg(i); +      } else if (strcmp(argv[i], "-dump_parse_top") == 0) { +	dump_top |= STAGE1; +	Swig_mark_arg(i); +      } else if (strcmp(argv[i], "-dump_xml") == 0) { +	dump_xml = 1; +	Swig_mark_arg(i); +      } else if (strcmp(argv[i], "-xmlout") == 0) { +	dump_xml = 1; +	Swig_mark_arg(i); +	if (argv[i + 1]) { +	  xmlout = NewString(argv[i + 1]); +	  Swig_mark_arg(i + 1); +	} else { +	  Swig_arg_error(); +	} +      } else if (strcmp(argv[i], "-nocontract") == 0) { +	Swig_mark_arg(i); +	Swig_contract_mode_set(0); +      } else if ((strcmp(argv[i], "-debug-typedef") == 0) || (strcmp(argv[i], "-dump_typedef") == 0)) { +	dump_typedef = 1; +	Swig_mark_arg(i); +      } else if ((strcmp(argv[i], "-debug-classes") == 0) || (strcmp(argv[i], "-dump_classes") == 0)) { +	dump_classes = 1; +	Swig_mark_arg(i); +      } else if ((strcmp(argv[i], "-debug-memory") == 0) || (strcmp(argv[i], "-dump_memory") == 0)) { +	memory_debug = 1; +	Swig_mark_arg(i); +      } else if (strcmp(argv[i], "-Fstandard") == 0) { +	Swig_error_msg_format(EMF_STANDARD); +	Swig_mark_arg(i); +      } else if (strcmp(argv[i], "-Fmicrosoft") == 0) { +	Swig_error_msg_format(EMF_MICROSOFT); +	Swig_mark_arg(i); +      } else if (strcmp(argv[i], "-O") == 0) { +	Wrapper_virtual_elimination_mode_set(1); +	Wrapper_fast_dispatch_mode_set(1); +	Swig_mark_arg(i); +      } else if (strcmp(argv[i], "-help") == 0) { +	fputs(usage1, stdout); +	fputs(usage2, stdout); +	fputs(usage3, stdout); +	fputs(usage4, stdout); +	Swig_mark_arg(i); +	help = 1; +      } +    } +  } +} + +static void SWIG_exit_handler(int status); + +int SWIG_main(int argc, char *argv[], const TargetLanguageModule *tlm) { +  char *c; + +  /* Set function for Exit() to call. */ +  SetExitHandler(SWIG_exit_handler); + +  /* Initialize the SWIG core */ +  Swig_init(); + +  // Default warning suppression +  Swig_warnfilter(EXTRA_WARNINGS, 1); + +  // Initialize the preprocessor +  Preprocessor_init(); + +  // Set lang to a dummy value if no target language was specified so we +  // can process options enough to handle -version, etc. +  lang = tlm ? tlm->fac() : new Language; + +  // Set up some default symbols (available in both SWIG interface files +  // and C files) + +  Preprocessor_define((DOH *) "SWIG 1", 0); +  Preprocessor_define((DOH *) "__STDC__", 0); + +  String *vers = Swig_package_version_hex(); +  Preprocessor_define(vers, 0); +  Delete(vers); + +  Swig_contract_mode_set(1); + +  /* Turn off directors mode */ +  Wrapper_director_mode_set(0); +  Wrapper_director_protected_mode_set(1); + +  // Inform the parser if the nested classes should be ignored unless explicitly told otherwise via feature:flatnested +  ignore_nested_classes = lang->nestedClassesSupport() == Language::NCS_Unknown ? 1 : 0; + +  kwargs_supported = lang->kwargsSupport() ? 1 : 0; + +  // Create Library search directories + +  // Check for SWIG_LIB environment variable +  if ((c = getenv("SWIG_LIB")) == (char *) 0) { +#if defined(_WIN32) +    char buf[MAX_PATH]; +    char *p; +    if (!(GetModuleFileName(0, buf, MAX_PATH) == 0 || (p = strrchr(buf, '\\')) == 0)) { +      *(p + 1) = '\0'; +      SwigLib = NewStringf("%sLib", buf); // Native windows installation path +    } else { +      SwigLib = NewStringf("");	// Unexpected error +    } +    if (Len(SWIG_LIB_WIN_UNIX) > 0) +      SwigLibWinUnix = NewString(SWIG_LIB_WIN_UNIX); // Unix installation path using a drive letter (for msys/mingw) +#else +    SwigLib = NewString(SWIG_LIB); +#endif +  } else { +    SwigLib = NewString(c); +  } + +  libfiles = NewList(); +  all_output_files = NewList(); + +  /* Check for SWIG_FEATURES environment variable */ + +  getoptions(argc, argv); + +  // Define the __cplusplus symbol +  if (CPlusPlus) +    Preprocessor_define((DOH *) "__cplusplus __cplusplus", 0); + +  // Parse language dependent options +  lang->main(argc, argv); + +  if (help) { +    Printf(stdout, "\nNote: 'swig -<lang> -help' displays options for a specific target language.\n\n"); +    Exit(EXIT_SUCCESS);	// Exit if we're in help mode +  } + +  // Check all of the options to make sure we're cool. +  // Don't check for an input file if -external-runtime is passed +  Swig_check_options(external_runtime ? 0 : 1); + +  if (CPlusPlus && cparse_cplusplusout) { +    Printf(stderr, "The -c++out option is for C input but C++ input has been requested via -c++\n"); +    Exit(EXIT_FAILURE); +  } + +  install_opts(argc, argv); + +  // Add language dependent directory to the search path +  { +    String *rl = NewString(""); +    Printf(rl, ".%sswig_lib%s%s", SWIG_FILE_DELIMITER, SWIG_FILE_DELIMITER, LangSubDir); +    Swig_add_directory(rl); +    if (SwigLibWinUnix) { +      rl = NewString(""); +      Printf(rl, "%s%s%s", SwigLibWinUnix, SWIG_FILE_DELIMITER, LangSubDir); +      Swig_add_directory(rl); +    } +    rl = NewString(""); +    Printf(rl, "%s%s%s", SwigLib, SWIG_FILE_DELIMITER, LangSubDir); +    Swig_add_directory(rl); +  } + +  Swig_add_directory((String *) "." SWIG_FILE_DELIMITER "swig_lib"); +  if (SwigLibWinUnix) +    Swig_add_directory((String *) SwigLibWinUnix); +  Swig_add_directory(SwigLib); + +  if (Verbose) { +    Printf(stdout, "Language subdirectory: %s\n", LangSubDir); +    Printf(stdout, "Search paths:\n"); +    List *sp = Swig_search_path(); +    Iterator s; +    for (s = First(sp); s.item; s = Next(s)) { +      Printf(stdout, "   %s\n", s.item); +    } +  } +  // handle the -external-runtime argument +  if (external_runtime) +    SWIG_dump_runtime(); + +  // If we made it this far, looks good. go for it.... + +  input_file = NewString(argv[argc - 1]); +  Swig_filename_correct(input_file); + +  // If the user has requested to check out a file, handle that +  if (checkout) { +    DOH *s; +    String *outfile = input_file; +    if (outfile_name) +      outfile = outfile_name; + +    if (Verbose) +      Printf(stdout, "Handling checkout...\n"); + +    s = Swig_include(input_file); +    if (!s) { +      Printf(stderr, "Unable to locate '%s' in the SWIG library.\n", input_file); +    } else { +      FILE *f = Swig_open(outfile); +      if (f) { +	fclose(f); +	Printf(stderr, "File '%s' already exists. Checkout aborted.\n", outfile); +      } else { +        File *f_outfile = NewFile(outfile, "w", SWIG_output_files()); +        if (!f_outfile) { +          FileErrorDisplay(outfile); +          Exit(EXIT_FAILURE); +        } else { +          if (Verbose) +            Printf(stdout, "'%s' checked out from the SWIG library.\n", outfile); +          Printv(f_outfile, s, NIL); +          Delete(f_outfile); +        } +      } +    } +  } else { +    // Run the preprocessor +    if (Verbose) +      Printf(stdout, "Preprocessing...\n"); + +    { +      int i; +      String *fs = NewString(""); +      FILE *df = Swig_open(input_file); +      if (!df) { +	df = Swig_include_open(input_file); +	if (!df) { +	  char *cfile = Char(input_file); +	  if (cfile && cfile[0] == '-') { +	    Printf(stderr, "Unable to find option or file '%s', ", input_file); +	    Printf(stderr, "Use 'swig -help' for more information.\n"); +	  } else { +	    Printf(stderr, "Unable to find file '%s'.\n", input_file); +	  } +	  Exit(EXIT_FAILURE); +	} else { +	  Swig_warning(WARN_DEPRECATED_INPUT_FILE, "SWIG", 1, "Use of the include path to find the input file is deprecated and will not work with ccache. Please include the path when specifying the input file.\n"); // so that behaviour is like c/c++ compilers +	} +      } + +      if (!tlm) { +	Printf(stderr, "No target language specified.\n"); +	Printf(stderr, "Use 'swig -help' for more information.\n"); +	Exit(EXIT_FAILURE); +      } + +      if (!no_cpp) { +	fclose(df); +	Printf(fs, "%%include <swig.swg>\n"); +	if (allkw) { +	  Printf(fs, "%%include <allkw.swg>\n"); +	} +	if (lang_config) { +	  Printf(fs, "\n%%include <%s>\n", lang_config); +	} +	Printf(fs, "%%include(maininput=\"%s\") \"%s\"\n", Swig_filename_escape(input_file), Swig_filename_escape(Swig_last_file())); +	for (i = 0; i < Len(libfiles); i++) { +	  Printf(fs, "\n%%include \"%s\"\n", Swig_filename_escape(Getitem(libfiles, i))); +	} +	Seek(fs, 0, SEEK_SET); +	cpps = Preprocessor_parse(fs); +	Delete(fs); +      } else { +	cpps = Swig_read_file(df); +	fclose(df); +      } +      if (Swig_error_count()) { +	Exit(EXIT_FAILURE); +      } +      if (cpp_only) { +	Printf(stdout, "%s", cpps); +	Exit(EXIT_SUCCESS); +      } +      if (depend) { +	if (!no_cpp) { +	  String *outfile; +          File *f_dependencies_file = 0; + +	  String *inputfile_filename = outcurrentdir ? Swig_file_filename(input_file): Copy(input_file); +	  String *basename = Swig_file_basename(inputfile_filename); +	  if (!outfile_name) { +	    if (CPlusPlus || lang->cplus_runtime_mode()) { +	      outfile = NewStringf("%s_wrap.%s", basename, cpp_extension); +	    } else { +	      outfile = NewStringf("%s_wrap.c", basename); +	    } +	  } else { +	    outfile = NewString(outfile_name); +	  } +	  if (dependencies_file && Len(dependencies_file) != 0) { +	    f_dependencies_file = NewFile(dependencies_file, "w", SWIG_output_files()); +	    if (!f_dependencies_file) { +	      FileErrorDisplay(dependencies_file); +	      Exit(EXIT_FAILURE); +	    } +	  } else if (!depend_only) { +	    String *filename = NewStringf("%s_wrap.%s", basename, depends_extension); +	    f_dependencies_file = NewFile(filename, "w", SWIG_output_files()); +	    if (!f_dependencies_file) { +	      FileErrorDisplay(filename); +	      Exit(EXIT_FAILURE); +	    } +	  } else +	    f_dependencies_file = stdout; +	  if (dependencies_target) { +	    Printf(f_dependencies_file, "%s: ", Swig_filename_escape_space(dependencies_target)); +	  } else { +	    Printf(f_dependencies_file, "%s: ", Swig_filename_escape_space(outfile)); +	  } +	  List *files = Preprocessor_depend(); +	  List *phony_targets = NewList(); +	  for (int i = 0; i < Len(files); i++) { +            int use_file = 1; +            if (depend == 2) { +              if ((Strncmp(Getitem(files, i), SwigLib, Len(SwigLib)) == 0) || (SwigLibWinUnix && (Strncmp(Getitem(files, i), SwigLibWinUnix, Len(SwigLibWinUnix)) == 0))) +                use_file = 0; +            } +            if (use_file) { +              Printf(f_dependencies_file, "\\\n  %s ", Swig_filename_escape_space(Getitem(files, i))); +              if (depend_phony) +                Append(phony_targets, Getitem(files, i)); +            } +	  } +	  Printf(f_dependencies_file, "\n"); +	  if (depend_phony) { +	    for (int i = 0; i < Len(phony_targets); i++) { +	      Printf(f_dependencies_file, "\n%s:\n", Swig_filename_escape_space(Getitem(phony_targets, i))); +	    } +	  } + +	  if (f_dependencies_file != stdout) +	    Delete(f_dependencies_file); +	  if (depend_only) +	    Exit(EXIT_SUCCESS); +	  Delete(inputfile_filename); +	  Delete(basename); +	  Delete(phony_targets); +	} else { +	  Printf(stderr, "Cannot generate dependencies with -nopreprocess\n"); +	  // Actually we could but it would be inefficient when just generating dependencies, as it would be done after Swig_cparse +	  Exit(EXIT_FAILURE); +	} +      } +      Seek(cpps, 0, SEEK_SET); +    } + +    /* Register a null file with the file handler */ +    Swig_register_filebyname("null", NewString("")); + +    // Pass control over to the specific language interpreter +    if (Verbose) { +      fprintf(stdout, "Starting language-specific parse...\n"); +      fflush(stdout); +    } + +    Node *top = Swig_cparse(cpps); + +    if (dump_top & STAGE1) { +      Printf(stdout, "debug-top stage 1\n"); +      Swig_print_tree(top); +    } +    if (dump_module & STAGE1) { +      Printf(stdout, "debug-module stage 1\n"); +      Swig_print_tree(Getattr(top, "module")); +    } +    if (!CPlusPlus) { +      if (Verbose) +	Printf(stdout, "Processing unnamed structs...\n"); +      Swig_nested_name_unnamed_c_structs(top); +    } +    Swig_extend_unused_check(); + +    if (Verbose) { +      Printf(stdout, "Processing types...\n"); +    } +    Swig_process_types(top); + +    if (dump_top & STAGE2) { +      Printf(stdout, "debug-top stage 2\n"); +      Swig_print_tree(top); +    } +    if (dump_module & STAGE2) { +      Printf(stdout, "debug-module stage 2\n"); +      Swig_print_tree(Getattr(top, "module")); +    } + +    if (Verbose) { +      Printf(stdout, "C++ analysis...\n"); +    } +    Swig_default_allocators(top); + +    if (CPlusPlus) { +      if (Verbose) +	Printf(stdout, "Processing nested classes...\n"); +      Swig_nested_process_classes(top); +    } + +    if (dump_top & STAGE3) { +      Printf(stdout, "debug-top stage 3\n"); +      Swig_print_tree(top); +    } +    if (top && (dump_module & STAGE3)) { +      Printf(stdout, "debug-module stage 3\n"); +      Swig_print_tree(Getattr(top, "module")); +    } + +    if (Verbose) { +      Printf(stdout, "Generating wrappers...\n"); +    } + +    if (top && dump_classes) { +      Hash *classes = Getattr(top, "classes"); +      if (classes) { +	Printf(stdout, "Classes\n"); +	Printf(stdout, "------------\n"); +	Iterator ki; +	for (ki = First(classes); ki.key; ki = Next(ki)) { +	  Printf(stdout, "%s\n", ki.key); +	} +      } +    } + +    if (dump_typedef) { +      SwigType_print_scope(); +    } + +    if (dump_symtabs) { +      Swig_symbol_print_tables(Swig_symbol_global_scope()); +      Swig_symbol_print_tables_summary(); +    } + +    if (dump_symbols) { +      Swig_symbol_print_symbols(); +    } + +    if (dump_csymbols) { +      Swig_symbol_print_csymbols(); +    } + +    if (dump_tags) { +      Swig_print_tags(top, 0); +    } +    if (top) { +      if (!Getattr(top, "name")) { +	Printf(stderr, "No module name specified using %%module or -module.\n"); +	Exit(EXIT_FAILURE); +      } else { +	/* Set some filename information on the object */ +	String *infile = scanner_get_main_input_file(); +	if (!infile) { +	  Printf(stderr, "Missing input file in preprocessed output.\n"); +	  Exit(EXIT_FAILURE); +	} +	Setattr(top, "infile", infile); // Note: if nopreprocess then infile is the original input file, otherwise input_file +	Setattr(top, "inputfile", input_file); + +	String *infile_filename = outcurrentdir ? Swig_file_filename(infile): Copy(infile); +	String *basename = Swig_file_basename(infile_filename); +	if (!outfile_name) { +	  if (CPlusPlus || lang->cplus_runtime_mode()) { +	    Setattr(top, "outfile", NewStringf("%s_wrap.%s", basename, cpp_extension)); +	  } else { +	    Setattr(top, "outfile", NewStringf("%s_wrap.c", basename)); +	  } +	} else { +	  Setattr(top, "outfile", outfile_name); +	} +	if (!outfile_name_h) { +	  Setattr(top, "outfile_h", NewStringf("%s_wrap.%s", basename, hpp_extension)); +	} else { +	  Setattr(top, "outfile_h", outfile_name_h); +	} +	configure_outdir(Getattr(top, "outfile")); +	if (Swig_contract_mode_get()) { +	  Swig_contracts(top); +	} + +	// Check the extension for a c/c++ file.  If so, we're going to declare everything we see as "extern" +	ForceExtern = check_extension(input_file); + +	if (tlm->status == Experimental) { +	  Swig_warning(WARN_LANG_EXPERIMENTAL, "SWIG", 1, "Experimental target language. " +	    "Target language %s specified by %s is an experimental language. " +	    "Please read about SWIG experimental languages, https://swig.org/Doc4.0/Introduction.html#Introduction_experimental_status.\n", +	    tlm->help ? tlm->help : "", tlm->name); +	} + +	lang->top(top); + +	Delete(infile_filename); +	Delete(basename); +      } +    } +    if (dump_lang_symbols) { +      lang->dumpSymbols(); +    } +    if (dump_top & STAGE4) { +      Printf(stdout, "debug-top stage 4\n"); +      Swig_print_tree(top); +    } +    if (dump_module & STAGE4) { +      Printf(stdout, "debug-module stage 4\n"); +      Swig_print_tree(Getattr(top, "module")); +    } +    if (dump_xml && top) { +      delete lang; +      lang = 0; +      Swig_print_xml(top, xmlout); +    } +    Delete(top); +  } +  if (tm_debug) +    Swig_typemap_debug(); +  if (memory_debug) +    DohMemoryDebug(); + +  char *outfiles = getenv("CCACHE_OUTFILES"); +  if (outfiles) { +    File *f_outfiles = NewFile(outfiles, "w", 0); +    if (!f_outfiles) { +      Printf(stderr, "Failed to write list of output files to the filename '%s' specified in CCACHE_OUTFILES environment variable - ", outfiles); +      FileErrorDisplay(outfiles); +      Exit(EXIT_FAILURE); +    } else { +      int i; +      for (i = 0; i < Len(all_output_files); i++) +        Printf(f_outfiles, "%s\n", Getitem(all_output_files, i)); +      Delete(f_outfiles); +    } +  } + +  // Deletes +  Delete(libfiles); +  Preprocessor_delete(); + +  while (freeze) { +  } + +  delete lang; + +  int error_count = werror ? Swig_warn_count() : 0; +  error_count += Swig_error_count(); + +  if (error_count != 0) +    Exit(EXIT_FAILURE); + +  return 0; +} + +/* ----------------------------------------------------------------------------- + * SWIG_exit_handler() + * + * Cleanup and either freeze or exit + * ----------------------------------------------------------------------------- */ + +static void SWIG_exit_handler(int status) { +  while (freeze) { +  } + +  if (status > 0) { +    CloseAllOpenFiles(); + +    /* Remove all generated files */ +    if (all_output_files) { +      for (int i = 0; i < Len(all_output_files); i++) { +	String *filename = Getitem(all_output_files, i); +	int removed = remove(Char(filename)); +	if (removed == -1) +	  fprintf(stderr, "On exit, could not delete file %s: %s\n", Char(filename), strerror(errno)); +      } +    } +  } +} diff --git a/contrib/tools/swig/Source/Modules/mzscheme.cxx b/contrib/tools/swig/Source/Modules/mzscheme.cxx new file mode 100644 index 00000000000..e22f8bb7adb --- /dev/null +++ b/contrib/tools/swig/Source/Modules/mzscheme.cxx @@ -0,0 +1,802 @@ +/* -----------------------------------------------------------------------------  + * This file is part of SWIG, which is licensed as a whole under version 3  + * (or any later version) of the GNU General Public License. Some additional + * terms also apply to certain portions of SWIG. The full details of the SWIG + * license and copyrights can be found in the LICENSE and COPYRIGHT files + * included with the SWIG source code as distributed by the SWIG developers + * and at https://www.swig.org/legal.html. + * + * mzscheme.cxx + * + * Mzscheme language module for SWIG. + * ----------------------------------------------------------------------------- */ + +#include "swigmod.h" +#include <ctype.h> + +static const char *usage = "\ +Mzscheme Options (available with -mzscheme)\n\ +     -declaremodule                - Create extension that declares a module\n\ +     -dynamic-load <lib>,[lib,...] - Do not link with these libraries, dynamic load them\n\ +     -noinit                       - Do not emit module initialization code\n\ +     -prefix <name>                - Set a prefix <name> to be prepended to all names\n\ +"; + +static String *fieldnames_tab = 0; +static String *convert_tab = 0; +static String *convert_proto_tab = 0; +static String *struct_name = 0; +static String *mangled_struct_name = 0; + +static String *prefix = 0; +static bool declaremodule = false; +static bool noinit = false; +static String *load_libraries = NULL; +static String *module = 0; +static const char *mzscheme_path = "mzscheme"; +static String *init_func_def = 0; + +static File *f_begin = 0; +static File *f_runtime = 0; +static File *f_header = 0; +static File *f_wrappers = 0; +static File *f_init = 0; + +// Used for garbage collection +static int exporting_destructor = 0; +static String *swigtype_ptr = 0; +static String *cls_swigtype = 0; + +class MZSCHEME:public Language { +public: + +  /* ------------------------------------------------------------ +   * main() +   * ------------------------------------------------------------ */ + +  virtual void main(int argc, char *argv[]) { + +    int i; + +     SWIG_library_directory(mzscheme_path); + +    // Look for certain command line options +    for (i = 1; i < argc; i++) { +      if (argv[i]) { +	if (strcmp(argv[i], "-help") == 0) { +	  fputs(usage, stdout); +	  Exit(EXIT_SUCCESS); +	} else if (strcmp(argv[i], "-prefix") == 0) { +	  if (argv[i + 1]) { +	    prefix = NewString(argv[i + 1]); +	    Swig_mark_arg(i); +	    Swig_mark_arg(i + 1); +	    i++; +	  } else { +	    Swig_arg_error(); +	  } +	} else if (strcmp(argv[i], "-declaremodule") == 0) { +	  declaremodule = true; +	  Swig_mark_arg(i); +	} else if (strcmp(argv[i], "-noinit") == 0) { +	  noinit = true; +	  Swig_mark_arg(i); +	} +	else if (strcmp(argv[i], "-dynamic-load") == 0) { +	  if (argv[i + 1]) { +	    Delete(load_libraries); +	    load_libraries = NewString(argv[i + 1]); +	    Swig_mark_arg(i++); +	    Swig_mark_arg(i); +	  } else { +	    Swig_arg_error(); +	  } +	} +      } +    } + +    // If a prefix has been specified make sure it ends in a '_' (not actually used!) +    if (prefix) { +      const char *px = Char(prefix); +      if (px[Len(prefix) - 1] != '_') +	Printf(prefix, "_"); +    } else +      prefix = NewString("swig_"); + +    // Add a symbol for this module + +    Preprocessor_define("SWIGMZSCHEME 1", 0); + +    // Set name of typemaps + +    SWIG_typemap_lang("mzscheme"); + +    // Read in default typemaps */ +    SWIG_config_file("mzscheme.swg"); +    allow_overloading(); + +  } + +  /* ------------------------------------------------------------ +   * top() +   * ------------------------------------------------------------ */ + +  virtual int top(Node *n) { + +    /* Initialize all of the output files */ +    String *outfile = Getattr(n, "outfile"); + +    f_begin = NewFile(outfile, "w", SWIG_output_files()); +    if (!f_begin) { +      FileErrorDisplay(outfile); +      Exit(EXIT_FAILURE); +    } +    f_runtime = NewString(""); +    f_init = NewString(""); +    f_header = NewString(""); +    f_wrappers = NewString(""); + +    /* Register file targets with the SWIG file handler */ +    Swig_register_filebyname("header", f_header); +    Swig_register_filebyname("wrapper", f_wrappers); +    Swig_register_filebyname("begin", f_begin); +    Swig_register_filebyname("runtime", f_runtime); + +    init_func_def = NewString(""); +    Swig_register_filebyname("init", init_func_def); + +    Swig_banner(f_begin); + +    Swig_obligatory_macros(f_runtime, "MZSCHEME"); + +    module = Getattr(n, "name"); + +    Language::top(n); + +    SwigType_emit_type_table(f_runtime, f_wrappers); +    if (!noinit) { +      if (declaremodule) { +	Printf(f_init, "#define SWIG_MZSCHEME_CREATE_MENV(env) scheme_primitive_module(scheme_intern_symbol(\"%s\"), env)\n", module); +      } else { +	Printf(f_init, "#define SWIG_MZSCHEME_CREATE_MENV(env) (env)\n"); +      } +      Printf(f_init, "%s\n", Char(init_func_def)); +      if (declaremodule) { +	Printf(f_init, "\tscheme_finish_primitive_module(menv);\n"); +      } +      Printf(f_init, "\treturn scheme_void;\n}\n"); +      Printf(f_init, "Scheme_Object *scheme_initialize(Scheme_Env *env) {\n"); + +      if (load_libraries) { +	Printf(f_init, "mz_set_dlopen_libraries(\"%s\");\n", load_libraries); +      } + +      Printf(f_init, "\treturn scheme_reload(env);\n"); +      Printf(f_init, "}\n"); + +      Printf(f_init, "Scheme_Object *scheme_module_name(void) {\n"); +      if (declaremodule) { +	Printf(f_init, "   return scheme_intern_symbol((char*)\"%s\");\n", module); +      } else { +	Printf(f_init, "   return scheme_make_symbol((char*)\"%s\");\n", module); +      } +      Printf(f_init, "}\n"); +    } + +    /* Close all of the files */ +    Dump(f_runtime, f_begin); +    Dump(f_header, f_begin); +    Dump(f_wrappers, f_begin); +    Wrapper_pretty_print(f_init, f_begin); +    Delete(f_header); +    Delete(f_wrappers); +    Delete(f_init); +    Delete(f_runtime); +    Delete(f_begin); +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * functionWrapper() +   * Create a function declaration and register it with the interpreter. +   * ------------------------------------------------------------ */ + +  void throw_unhandled_mzscheme_type_error(SwigType *d) { +    Swig_warning(WARN_TYPEMAP_UNDEF, input_file, line_number, "Unable to handle type %s.\n", SwigType_str(d, 0)); +  } + +  /* Return true iff T is a pointer type */ + +  int +   is_a_pointer(SwigType *t) { +    return SwigType_ispointer(SwigType_typedef_resolve_all(t)); +  } + +  virtual int functionWrapper(Node *n) { +    char *iname = GetChar(n, "sym:name"); +    SwigType *d = Getattr(n, "type"); +    ParmList *l = Getattr(n, "parms"); +    Parm *p; + +    Wrapper *f = NewWrapper(); +    String *proc_name = NewString(""); +    String *target = NewString(""); +    String *arg = NewString(""); +    String *cleanup = NewString(""); +    String *outarg = NewString(""); +    String *build = NewString(""); +    String *tm; +    int i = 0; +    int numargs; +    int numreq; +    String *overname = 0; + +    if (load_libraries) { +      ParmList *parms = Getattr(n, "parms"); +      SwigType *type = Getattr(n, "type"); +      String *name = NewString("caller"); +      Setattr(n, "wrap:action", Swig_cresult(type, Swig_cresult_name(), Swig_cfunction_call(name, parms))); +    } + +    // Make a wrapper name for this +    String *wname = Swig_name_wrapper(iname); +    if (Getattr(n, "sym:overloaded")) { +      overname = Getattr(n, "sym:overname"); +    } else { +      if (!addSymbol(iname, n)) { +        DelWrapper(f); +	return SWIG_ERROR; +      } +    } +    if (overname) { +      Append(wname, overname); +    } +    Setattr(n, "wrap:name", wname); + +    // Build the name for Scheme. +    Printv(proc_name, iname, NIL); +    Replaceall(proc_name, "_", "-"); + +    // writing the function wrapper function +    Printv(f->def, "static Scheme_Object *", wname, " (", NIL); +    Printv(f->def, "int argc, Scheme_Object **argv", NIL); +    Printv(f->def, ")\n{", NIL); + +    /* Define the scheme name in C. This define is used by several +       macros. */ +    Printv(f->def, "#define FUNC_NAME \"", proc_name, "\"", NIL); + +    // Emit all of the local variables for holding arguments. +    emit_parameter_variables(l, f); + +    /* Attach the standard typemaps */ +    emit_attach_parmmaps(l, f); +    Setattr(n, "wrap:parms", l); + +    numargs = emit_num_arguments(l); +    numreq = emit_num_required(l); + +    /* Add the holder for the pointer to the function to be opened */ +    if (load_libraries) { +      Wrapper_add_local(f, "_function_loaded", "static int _function_loaded=(1==0)"); +      Wrapper_add_local(f, "_the_function", "static void *_the_function=NULL"); +      { +	String *parms = ParmList_protostr(l); +	String *func = NewStringf("(*caller)(%s)", parms); +	Wrapper_add_local(f, "caller", SwigType_lstr(d, func));	/*"(*caller)()")); */ +      } +    } + +    // adds local variables +    Wrapper_add_local(f, "lenv", "int lenv = 1"); +    Wrapper_add_local(f, "values", "Scheme_Object *values[MAXVALUES]"); + +    if (load_libraries) { +      Printf(f->code, "if (!_function_loaded) { _the_function=mz_load_function(\"%s\");_function_loaded=(1==1); }\n", iname); +      Printf(f->code, "if (!_the_function) { scheme_signal_error(\"Cannot load C function '%s'\"); }\n", iname); +      Printf(f->code, "caller=_the_function;\n"); +    } + +    // Now write code to extract the parameters (this is super ugly) + +    for (i = 0, p = l; i < numargs; i++) { +      /* Skip ignored arguments */ + +      while (checkAttribute(p, "tmap:in:numinputs", "0")) { +	p = Getattr(p, "tmap:in:next"); +      } + +      SwigType *pt = Getattr(p, "type"); +      String *ln = Getattr(p, "lname"); + +      // Produce names of source and target +      Clear(target); +      Clear(arg); +      String *source = NewStringf("argv[%d]", i); +      Printf(target, "%s", ln); +      Printv(arg, Getattr(p, "name"), NIL); + +      if (i >= numreq) { +	Printf(f->code, "if (argc > %d) {\n", i); +      } +      // Handle parameter types. +      if ((tm = Getattr(p, "tmap:in"))) { +	Replaceall(tm, "$input", source); +	Setattr(p, "emit:input", source); +	Printv(f->code, tm, "\n", NIL); +	p = Getattr(p, "tmap:in:next"); +      } else { +	// no typemap found +	// check if typedef and resolve +	throw_unhandled_mzscheme_type_error(pt); +	p = nextSibling(p); +      } +      if (i >= numreq) { +	Printf(f->code, "}\n"); +      } +      Delete(source); +    } + +    /* Insert constraint checking code */ +    for (p = l; p;) { +      if ((tm = Getattr(p, "tmap:check"))) { +	Printv(f->code, tm, "\n", NIL); +	p = Getattr(p, "tmap:check:next"); +      } else { +	p = nextSibling(p); +      } +    } + +    // Pass output arguments back to the caller. + +    for (p = l; p;) { +      if ((tm = Getattr(p, "tmap:argout"))) { +	Replaceall(tm, "$arg", Getattr(p, "emit:input")); +	Replaceall(tm, "$input", Getattr(p, "emit:input")); +	Printv(outarg, tm, "\n", NIL); +	p = Getattr(p, "tmap:argout:next"); +      } else { +	p = nextSibling(p); +      } +    } + +    // Free up any memory allocated for the arguments. + +    /* Insert cleanup code */ +    for (p = l; p;) { +      if ((tm = Getattr(p, "tmap:freearg"))) { +	Printv(cleanup, tm, "\n", NIL); +	p = Getattr(p, "tmap:freearg:next"); +      } else { +	p = nextSibling(p); +      } +    } + +    // Now write code to make the function call + +    String *actioncode = emit_action(n); + +    // Now have return value, figure out what to do with it. +    if ((tm = Swig_typemap_lookup_out("out", n, Swig_cresult_name(), f, actioncode))) { +      Replaceall(tm, "$result", "values[0]"); +      if (GetFlag(n, "feature:new")) +	Replaceall(tm, "$owner", "1"); +      else +	Replaceall(tm, "$owner", "0"); +      Printv(f->code, tm, "\n", NIL); +    } else { +      throw_unhandled_mzscheme_type_error(d); +    } +    emit_return_variable(n, d, f); + +    // Dump the argument output code +    Printv(f->code, Char(outarg), NIL); + +    // Dump the argument cleanup code +    Printv(f->code, Char(cleanup), NIL); + +    // Look for any remaining cleanup + +    if (GetFlag(n, "feature:new")) { +      if ((tm = Swig_typemap_lookup("newfree", n, Swig_cresult_name(), 0))) { +	Printv(f->code, tm, "\n", NIL); +      } +    } +    // Free any memory allocated by the function being wrapped.. + +    if ((tm = Swig_typemap_lookup("ret", n, Swig_cresult_name(), 0))) { +      Printv(f->code, tm, "\n", NIL); +    } +    // Wrap things up (in a manner of speaking) + +    Printv(f->code, tab4, "return SWIG_MzScheme_PackageValues(lenv, values);\n", NIL); +    Printf(f->code, "#undef FUNC_NAME\n"); +    Printv(f->code, "}\n", NIL); + +    /* Substitute the function name */ +    Replaceall(f->code, "$symname", iname); + +    Wrapper_print(f, f_wrappers); + +    if (!Getattr(n, "sym:overloaded")) { + +      // Now register the function +      char temp[256]; +      sprintf(temp, "%d", numargs); +      if (exporting_destructor) { +	Printf(init_func_def, "SWIG_TypeClientData(SWIGTYPE%s, (void *) %s);\n", swigtype_ptr, wname); +      } +      Printf(init_func_def, "scheme_add_global(\"%s\", scheme_make_prim_w_arity(%s,\"%s\",%d,%d),menv);\n", proc_name, wname, proc_name, numreq, numargs); +    } else { +      if (!Getattr(n, "sym:nextSibling")) { +	/* Emit overloading dispatch function */ + +	int maxargs; +	String *dispatch = Swig_overload_dispatch(n, "return %s(argc,argv);", &maxargs); + +	/* Generate a dispatch wrapper for all overloaded functions */ + +	Wrapper *df = NewWrapper(); +	String *dname = Swig_name_wrapper(iname); + +	Printv(df->def, "static Scheme_Object *\n", dname, "(int argc, Scheme_Object **argv) {", NIL); +	Printv(df->code, dispatch, "\n", NIL); +	Printf(df->code, "scheme_signal_error(\"No matching function for overloaded '%s'\");\n", iname); +	Printf(df->code, "return NULL;\n"); +	Printv(df->code, "}\n", NIL); +	Wrapper_print(df, f_wrappers); +	Printf(init_func_def, "scheme_add_global(\"%s\", scheme_make_prim_w_arity(%s,\"%s\",%d,%d),menv);\n", proc_name, dname, proc_name, 0, maxargs); +	DelWrapper(df); +	Delete(dispatch); +	Delete(dname); +      } +    } + +    Delete(proc_name); +    Delete(target); +    Delete(arg); +    Delete(outarg); +    Delete(cleanup); +    Delete(build); +    DelWrapper(f); +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * variableWrapper() +   * +   * Create a link to a C variable. +   * This creates a single function _wrap_swig_var_varname(). +   * This function takes a single optional argument.   If supplied, it means +   * we are setting this variable to some value.  If omitted, it means we are +   * simply evaluating this variable.  Either way, we return the variables +   * value. +   * ------------------------------------------------------------ */ + +  virtual int variableWrapper(Node *n) { + +    char *name = GetChar(n, "name"); +    char *iname = GetChar(n, "sym:name"); +    SwigType *t = Getattr(n, "type"); + +    String *proc_name = NewString(""); +    String *tm; +    String *tm2 = NewString(""); +    String *argnum = NewString("0"); +    String *arg = NewString("argv[0]"); +    Wrapper *f; + +    if (!addSymbol(iname, n)) +      return SWIG_ERROR; + +    f = NewWrapper(); + +    // evaluation function names +    String *var_name = Swig_name_wrapper(iname); + +    // Build the name for scheme. +    Printv(proc_name, iname, NIL); +    Replaceall(proc_name, "_", "-"); +    Setattr(n, "wrap:name", proc_name); + +    if ((SwigType_type(t) != T_USER) || (is_a_pointer(t))) { + +      Printf(f->def, "static Scheme_Object *%s(int argc, Scheme_Object** argv) {\n", var_name); +      Printv(f->def, "#define FUNC_NAME \"", proc_name, "\"", NIL); + +      Wrapper_add_local(f, "swig_result", "Scheme_Object *swig_result"); + +      if (!GetFlag(n, "feature:immutable")) { +	/* Check for a setting of the variable value */ +	Printf(f->code, "if (argc) {\n"); +	if ((tm = Swig_typemap_lookup("varin", n, name, 0))) { +	  Replaceall(tm, "$input", "argv[0]"); +	  Replaceall(tm, "$argnum", "1"); +	  emit_action_code(n, f->code, tm); +	} else { +	  throw_unhandled_mzscheme_type_error(t); +	} +	Printf(f->code, "}\n"); +      } +      // Now return the value of the variable (regardless +      // of evaluating or setting) + +      if ((tm = Swig_typemap_lookup("varout", n, name, 0))) { +	Replaceall(tm, "$result", "swig_result"); +	/* Printf (f->code, "%s\n", tm); */ +	emit_action_code(n, f->code, tm); +      } else { +	throw_unhandled_mzscheme_type_error(t); +      } +      Printf(f->code, "\nreturn swig_result;\n"); +      Printf(f->code, "#undef FUNC_NAME\n"); +      Printf(f->code, "}\n"); + +      Wrapper_print(f, f_wrappers); + +      // Now add symbol to the MzScheme interpreter + +      Printv(init_func_def, +	     "scheme_add_global(\"", proc_name, "\", scheme_make_prim_w_arity(", var_name, ", \"", proc_name, "\", ", "0", ", ", "1", "), menv);\n", NIL); + +    } else { +      Swig_warning(WARN_TYPEMAP_VAR_UNDEF, input_file, line_number, "Unsupported variable type %s (ignored).\n", SwigType_str(t, 0)); +    } +    Delete(var_name); +    Delete(proc_name); +    Delete(argnum); +    Delete(arg); +    Delete(tm2); +    DelWrapper(f); +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * constantWrapper() +   * ------------------------------------------------------------ */ + +  virtual int constantWrapper(Node *n) { +    char *name = GetChar(n, "name"); +    char *iname = GetChar(n, "sym:name"); +    SwigType *type = Getattr(n, "type"); +    String *value = Getattr(n, "value"); + +    String *var_name = NewString(""); +    String *proc_name = NewString(""); +    String *rvalue = NewString(""); +    String *temp = NewString(""); +    String *tm; + +    // Make a static variable; + +    Printf(var_name, "_wrap_const_%s", Swig_name_mangle(Getattr(n, "sym:name"))); + +    // Build the name for scheme. +    Printv(proc_name, iname, NIL); +    Replaceall(proc_name, "_", "-"); + +    if ((SwigType_type(type) == T_USER) && (!is_a_pointer(type))) { +      Swig_warning(WARN_TYPEMAP_CONST_UNDEF, input_file, line_number, "Unsupported constant value.\n"); +      return SWIG_NOWRAP; +    } +    // See if there's a typemap + +    Printv(rvalue, value, NIL); +    if ((SwigType_type(type) == T_CHAR) && (is_a_pointer(type) == 1)) { +      temp = Copy(rvalue); +      Clear(rvalue); +      Printv(rvalue, "\"", temp, "\"", NIL); +    } +    if ((SwigType_type(type) == T_CHAR) && (is_a_pointer(type) == 0)) { +      Delete(temp); +      temp = Copy(rvalue); +      Clear(rvalue); +      Printv(rvalue, "'", temp, "'", NIL); +    } +    if ((tm = Swig_typemap_lookup("constant", n, name, 0))) { +      Replaceall(tm, "$value", rvalue); +      Printf(f_init, "%s\n", tm); +    } else { +      // Create variable and assign it a value + +      Printf(f_header, "static %s = ", SwigType_lstr(type, var_name)); +      bool is_enum_item = (Cmp(nodeType(n), "enumitem") == 0); +      if ((SwigType_type(type) == T_STRING)) { +	Printf(f_header, "\"%s\";\n", value); +      } else if (SwigType_type(type) == T_CHAR && !is_enum_item) { +	Printf(f_header, "\'%s\';\n", value); +      } else { +	Printf(f_header, "%s;\n", value); +      } + +      // Now create a variable declaration + +      { +	/* Hack alert: will cleanup later -- Dave */ +	Node *nn = NewHash(); +	Setfile(nn, Getfile(n)); +	Setline(nn, Getline(n)); +	Setattr(nn, "name", var_name); +	Setattr(nn, "sym:name", iname); +	Setattr(nn, "type", type); +	SetFlag(nn, "feature:immutable"); +	variableWrapper(nn); +	Delete(nn); +      } +    } +    Delete(proc_name); +    Delete(rvalue); +    Delete(temp); +    return SWIG_OK; +  } + +  virtual int destructorHandler(Node *n) { +    exporting_destructor = true; +    Language::destructorHandler(n); +    exporting_destructor = false; +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * classHandler() +   * ------------------------------------------------------------ */ +  virtual int classHandler(Node *n) { +    String *mangled_classname = 0; +    String *real_classname = 0; +    String *scm_structname = NewString(""); +    SwigType *ctype_ptr = NewStringf("p.%s", getClassType()); + +    SwigType *t = NewStringf("p.%s", Getattr(n, "name")); +    swigtype_ptr = SwigType_manglestr(t); +    Delete(t); + +    cls_swigtype = SwigType_manglestr(Getattr(n, "name")); + + +    fieldnames_tab = NewString(""); +    convert_tab = NewString(""); +    convert_proto_tab = NewString(""); + +    struct_name = Getattr(n, "sym:name"); +    mangled_struct_name = Swig_name_mangle(Getattr(n, "sym:name")); + +    Printv(scm_structname, struct_name, NIL); +    Replaceall(scm_structname, "_", "-"); + +    real_classname = Getattr(n, "name"); +    mangled_classname = Swig_name_mangle(real_classname); + +    Printv(fieldnames_tab, "static const char *_swig_struct_", cls_swigtype, "_field_names[] = { \n", NIL); + +    Printv(convert_proto_tab, "static Scheme_Object *_swig_convert_struct_", cls_swigtype, "(", SwigType_str(ctype_ptr, "ptr"), ");\n", NIL); + +    Printv(convert_tab, "static Scheme_Object *_swig_convert_struct_", cls_swigtype, "(", SwigType_str(ctype_ptr, "ptr"), ")\n {\n", NIL); + +    Printv(convert_tab, +	   tab4, "Scheme_Object *obj;\n", tab4, "Scheme_Object *fields[_swig_struct_", cls_swigtype, "_field_names_cnt];\n", tab4, "int i = 0;\n\n", NIL); + +    /* Generate normal wrappers */ +    Language::classHandler(n); + +    Printv(convert_tab, tab4, "obj = scheme_make_struct_instance(", "_swig_struct_type_", cls_swigtype, ", i, fields);\n", NIL); +    Printv(convert_tab, tab4, "return obj;\n}\n\n", NIL); + +    Printv(fieldnames_tab, "};\n", NIL); + +    Printv(f_header, "static Scheme_Object *_swig_struct_type_", cls_swigtype, ";\n", NIL); + +    Printv(f_header, fieldnames_tab, NIL); +    Printv(f_header, "#define  _swig_struct_", cls_swigtype, "_field_names_cnt (sizeof(_swig_struct_", cls_swigtype, "_field_names)/sizeof(char*))\n", NIL); + +    Printv(f_header, convert_proto_tab, NIL); +    Printv(f_wrappers, convert_tab, NIL); + +    Printv(init_func_def, "_swig_struct_type_", cls_swigtype, +	   " = SWIG_MzScheme_new_scheme_struct(menv, \"", scm_structname, "\", ", +	   "_swig_struct_", cls_swigtype, "_field_names_cnt,", "(char**) _swig_struct_", cls_swigtype, "_field_names);\n", NIL); + +    Delete(mangled_classname); +    Delete(swigtype_ptr); +    swigtype_ptr = 0; +    Delete(fieldnames_tab); +    Delete(convert_tab); +    Delete(ctype_ptr); +    Delete(convert_proto_tab); +    struct_name = 0; +    mangled_struct_name = 0; +    Delete(cls_swigtype); +    cls_swigtype = 0; + +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * membervariableHandler() +   * ------------------------------------------------------------ */ + +  virtual int membervariableHandler(Node *n) { +    Language::membervariableHandler(n); + +    if (!is_smart_pointer()) { +      String *symname = Getattr(n, "sym:name"); +      String *name = Getattr(n, "name"); +      SwigType *type = Getattr(n, "type"); +      String *swigtype = SwigType_manglestr(Getattr(n, "type")); +      String *tm = 0; +      String *access_mem = NewString(""); +      SwigType *ctype_ptr = NewStringf("p.%s", Getattr(n, "type")); + +      Printv(fieldnames_tab, tab4, "\"", symname, "\",\n", NIL); +      Printv(access_mem, "(ptr)->", name, NIL); +      if ((SwigType_type(type) == T_USER) && (!is_a_pointer(type))) { +	Printv(convert_tab, tab4, "fields[i++] = ", NIL); +	Printv(convert_tab, "_swig_convert_struct_", swigtype, "((", SwigType_str(ctype_ptr, 0), ")&((ptr)->", name, "));\n", NIL); +      } else if ((tm = Swig_typemap_lookup("varout", n, access_mem, 0))) { +	Replaceall(tm, "$result", "fields[i++]"); +	Printv(convert_tab, tm, "\n", NIL); +      } else +	Swig_warning(WARN_TYPEMAP_VAR_UNDEF, input_file, line_number, "Unsupported member variable type %s (ignored).\n", SwigType_str(type, 0)); + +      Delete(access_mem); +    } +    return SWIG_OK; +  } + + +  /* ------------------------------------------------------------ +   * validIdentifier() +   * ------------------------------------------------------------ */ + +  virtual int validIdentifier(String *s) { +    char *c = Char(s); +    /* Check whether we have an R5RS identifier. */ +    /* <identifier> --> <initial> <subsequent>* | <peculiar identifier> */ +    /* <initial> --> <letter> | <special initial> */ +    if (!(isalpha(*c) || (*c == '!') || (*c == '$') || (*c == '%') +	  || (*c == '&') || (*c == '*') || (*c == '/') || (*c == ':') +	  || (*c == '<') || (*c == '=') || (*c == '>') || (*c == '?') +	  || (*c == '^') || (*c == '_') || (*c == '~'))) { +      /* <peculiar identifier> --> + | - | ... */ +      if ((strcmp(c, "+") == 0) +	  || strcmp(c, "-") == 0 || strcmp(c, "...") == 0) +	return 1; +      else +	return 0; +    } +    /* <subsequent> --> <initial> | <digit> | <special subsequent> */ +    while (*c) { +      if (!(isalnum(*c) || (*c == '!') || (*c == '$') || (*c == '%') +	    || (*c == '&') || (*c == '*') || (*c == '/') || (*c == ':') +	    || (*c == '<') || (*c == '=') || (*c == '>') || (*c == '?') +	    || (*c == '^') || (*c == '_') || (*c == '~') || (*c == '+') +	    || (*c == '-') || (*c == '.') || (*c == '@'))) +	return 0; +      c++; +    } +    return 1; +  } + +  String *runtimeCode() { +    String *s = Swig_include_sys("mzrun.swg"); +    if (!s) { +      Printf(stderr, "*** Unable to open 'mzrun.swg'\n"); +      s = NewString(""); +    } +    return s; +  } + +  String *defaultExternalRuntimeFilename() { +    return NewString("swigmzrun.h"); +  } +}; + +/* ----------------------------------------------------------------------------- + * swig_mzscheme()    - Instantiate module + * ----------------------------------------------------------------------------- */ + +static Language *new_swig_mzscheme() { +  return new MZSCHEME(); +} +extern "C" Language *swig_mzscheme(void) { +  return new_swig_mzscheme(); +} diff --git a/contrib/tools/swig/Source/Modules/nested.cxx b/contrib/tools/swig/Source/Modules/nested.cxx new file mode 100644 index 00000000000..d027eebe5ba --- /dev/null +++ b/contrib/tools/swig/Source/Modules/nested.cxx @@ -0,0 +1,453 @@ +/* ----------------------------------------------------------------------------- + * This file is part of SWIG, which is licensed as a whole under version 3  + * (or any later version) of the GNU General Public License. Some additional + * terms also apply to certain portions of SWIG. The full details of the SWIG + * license and copyrights can be found in the LICENSE and COPYRIGHT files + * included with the SWIG source code as distributed by the SWIG developers + * and at https://www.swig.org/legal.html. + * + * nested.cxx + * + * Nested structs support + * ----------------------------------------------------------------------------- */ + +#include "swigmod.h" +#include "cparse.h" + +// Nested classes processing section +static Hash *classhash = 0; + +static String *make_name(Node *n, String *name, SwigType *decl) { +  int destructor = name && (*(Char(name)) == '~'); +  if (String *yyrename = Getattr(n, "class_rename")) { +    String *s = NewString(yyrename); +    Delattr(n, "class_rename"); +    if (destructor && (*(Char(s)) != '~')) { +      Insert(s, 0, "~"); +    } +    return s; +  } + +  if (!name) +    return 0; +  return Swig_name_make(n, 0, name, decl, 0); +} + +// C version of add_symbols() +static void add_symbols_c(Node *n) { +  String *decl; +  String *wrn = 0; +  String *symname = 0; +  int iscdecl = Cmp(nodeType(n), "cdecl") == 0; +  Setattr(n, "ismember", "1"); +  Setattr(n, "access", "public"); +  if (Getattr(n, "sym:name")) +    return; +  decl = Getattr(n, "decl"); +  if (!SwigType_isfunction(decl)) { +    String *name = Getattr(n, "name"); +    String *makename = Getattr(n, "parser:makename"); +    if (iscdecl) { +      String *storage = Getattr(n, "storage"); +      if (Cmp(storage, "typedef") == 0) { +	Setattr(n, "kind", "typedef"); +      } else { +	SwigType *type = Getattr(n, "type"); +	String *value = Getattr(n, "value"); +	Setattr(n, "kind", "variable"); +	if (value && Len(value)) { +	  Setattr(n, "hasvalue", "1"); +	} +	if (type) { +	  SwigType *ty; +	  SwigType *tmp = 0; +	  if (decl) { +	    ty = tmp = Copy(type); +	    SwigType_push(ty, decl); +	  } else { +	    ty = type; +	  } +	  if (!SwigType_ismutable(ty)) { +	    SetFlag(n, "hasconsttype"); +	    SetFlag(n, "feature:immutable"); +	  } +	  if (tmp) +	    Delete(tmp); +	} +	if (!type) { +	  Printf(stderr, "notype name %s\n", name); +	} +      } +    } +    Swig_features_get(Swig_cparse_features(), 0, name, 0, n); +    if (makename) { +      symname = make_name(n, makename, 0); +      Delattr(n, "parser:makename");	/* temporary information, don't leave it hanging around */ +    } else { +      makename = name; +      symname = make_name(n, makename, 0); +    } + +    if (!symname) { +      symname = Copy(Getattr(n, "unnamed")); +    } +    if (symname) { +      wrn = Swig_name_warning(n, 0, symname, 0); +    } +  } else { +    String *name = Getattr(n, "name"); +    SwigType *fdecl = Copy(decl); +    SwigType *fun = SwigType_pop_function(fdecl); +    if (iscdecl) { +      Setattr(n, "kind", "function"); +    } + +    Swig_features_get(Swig_cparse_features(), 0, name, fun, n); + +    symname = make_name(n, name, fun); +    wrn = Swig_name_warning(n, 0, symname, fun); + +    Delete(fdecl); +    Delete(fun); + +  } +  if (!symname) +    return; +  if (GetFlag(n, "feature:ignore")) { +    /* Only add to C symbol table and continue */ +    Swig_symbol_add(0, n); +  } else if (strncmp(Char(symname), "$ignore", 7) == 0) { +    char *c = Char(symname) + 7; +    SetFlag(n, "feature:ignore"); +    if (strlen(c)) { +      SWIG_WARN_NODE_BEGIN(n); +      Swig_warning(0, Getfile(n), Getline(n), "%s\n", c + 1); +      SWIG_WARN_NODE_END(n); +    } +    Swig_symbol_add(0, n); +  } else { +    Node *c; +    if ((wrn) && (Len(wrn))) { +      String *metaname = symname; +      if (!Getmeta(metaname, "already_warned")) { +	SWIG_WARN_NODE_BEGIN(n); +	Swig_warning(0, Getfile(n), Getline(n), "%s\n", wrn); +	SWIG_WARN_NODE_END(n); +	Setmeta(metaname, "already_warned", "1"); +      } +    } +    c = Swig_symbol_add(symname, n); + +    if (c != n) { +      /* symbol conflict attempting to add in the new symbol */ +      if (Getattr(n, "sym:weak")) { +	Setattr(n, "sym:name", symname); +      } else { +	String *e = NewStringEmpty(); +	String *en = NewStringEmpty(); +	String *ec = NewStringEmpty(); +	int redefined = Swig_need_redefined_warn(n, c, true); +	if (redefined) { +	  Printf(en, "Identifier '%s' redefined (ignored)", symname); +	  Printf(ec, "previous definition of '%s'", symname); +	} else { +	  Printf(en, "Redundant redeclaration of '%s'", symname); +	  Printf(ec, "previous declaration of '%s'", symname); +	} +	if (Cmp(symname, Getattr(n, "name"))) { +	  Printf(en, " (Renamed from '%s')", SwigType_namestr(Getattr(n, "name"))); +	} +	Printf(en, ","); +	if (Cmp(symname, Getattr(c, "name"))) { +	  Printf(ec, " (Renamed from '%s')", SwigType_namestr(Getattr(c, "name"))); +	} +	Printf(ec, "."); +	SWIG_WARN_NODE_BEGIN(n); +	if (redefined) { +	  Swig_warning(WARN_PARSE_REDEFINED, Getfile(n), Getline(n), "%s\n", en); +	  Swig_warning(WARN_PARSE_REDEFINED, Getfile(c), Getline(c), "%s\n", ec); +	} else { +	  Swig_warning(WARN_PARSE_REDUNDANT, Getfile(n), Getline(n), "%s\n", en); +	  Swig_warning(WARN_PARSE_REDUNDANT, Getfile(c), Getline(c), "%s\n", ec); +	} +	SWIG_WARN_NODE_END(n); +	Printf(e, "%s:%d:%s\n%s:%d:%s\n", Getfile(n), Getline(n), en, Getfile(c), Getline(c), ec); +	Setattr(n, "error", e); +	Delete(e); +	Delete(en); +	Delete(ec); +      } +    } +  } +  Delete(symname); +} + +/* Strips C-style and C++-style comments from string in-place. */ +static void strip_comments(char *string) { +  int state = 0; +  /* +   * 0 - not in comment +   * 1 - in c-style comment +   * 2 - in c++-style comment +   * 3 - in string +   * 4 - after reading / not in comments +   * 5 - after reading * in c-style comments +   * 6 - after reading \ in strings +   */ +  char *c = string; +  while (*c) { +    switch (state) { +    case 0: +      if (*c == '\"') +	state = 3; +      else if (*c == '/') +	state = 4; +      break; +    case 1: +      if (*c == '*') +	state = 5; +      *c = ' '; +      break; +    case 2: +      if (*c == '\n') +	state = 0; +      else +	*c = ' '; +      break; +    case 3: +      if (*c == '\"') +	state = 0; +      else if (*c == '\\') +	state = 6; +      break; +    case 4: +      if (*c == '/') { +	*(c - 1) = ' '; +	*c = ' '; +	state = 2; +      } else if (*c == '*') { +	*(c - 1) = ' '; +	*c = ' '; +	state = 1; +      } else +	state = 0; +      break; +    case 5: +      if (*c == '/') +	state = 0; +      else +	state = 1; +      *c = ' '; +      break; +    case 6: +      state = 3; +      break; +    } +    ++c; +  } +} + +// Create a %insert with a typedef to make a new name visible to C +static Node *create_insert(Node *n, bool noTypedef = false) { +  // format a typedef +  String *ccode = Getattr(n, "code"); +  Push(ccode, " "); +  if (noTypedef) { +    Push(ccode, Getattr(n, "name")); +    Push(ccode, " "); +    Push(ccode, Getattr(n, "kind")); +  } else { +    Push(ccode, Getattr(n, "kind")); +    Push(ccode, "typedef "); +    Append(ccode, " "); +    Append(ccode, Getattr(n, "tdname")); +  } +  Append(ccode, ";"); + +  /* Strip comments - further code may break in presence of comments. */ +  strip_comments(Char(ccode)); + +  /* Make all SWIG created typedef structs/unions/classes unnamed else +     redefinition errors occur - nasty hack alert. */ +  if (!noTypedef) { +    const char *types_array[3] = { "struct", "union", "class" }; +    for (int i = 0; i < 3; i++) { +      char *code_ptr = Char(ccode); +      while (code_ptr) { +	/* Replace struct name (as in 'struct name {...}' ) with whitespace +	   name will be between struct and opening brace */ + +	code_ptr = strstr(code_ptr, types_array[i]); +	if (code_ptr) { +	  char *open_bracket_pos; +	  code_ptr += strlen(types_array[i]); +	  open_bracket_pos = strchr(code_ptr, '{'); +	  if (open_bracket_pos) { +	    /* Make sure we don't have something like struct A a; */ +	    char *semi_colon_pos = strchr(code_ptr, ';'); +	    if (!(semi_colon_pos && (semi_colon_pos < open_bracket_pos))) +	      while (code_ptr < open_bracket_pos) +		*code_ptr++ = ' '; +	  } +	} +      } +    } +  } +  { +    /* Remove SWIG directive %constant which may be left in the SWIG created typedefs */ +    char *code_ptr = Char(ccode); +    while (code_ptr) { +      code_ptr = strstr(code_ptr, "%constant"); +      if (code_ptr) { +	char *directive_end_pos = strchr(code_ptr, ';'); +	if (directive_end_pos) { +	  while (code_ptr <= directive_end_pos) +	    *code_ptr++ = ' '; +	} +      } +    } +  } +  Node *newnode = NewHash(); +  set_nodeType(newnode, "insert"); +  Setfile(newnode, Getfile(n)); +  Setline(newnode, Getline(n)); +  String *code = NewStringEmpty(); +  Wrapper_pretty_print(ccode, code); +  Setattr(newnode, "code", code); +  Delete(code); +  Delattr(n, "code"); +  return newnode; +} + +static void insertNodeAfter(Node *n, Node *c) { +  Node *g = parentNode(n); +  set_parentNode(c, g); +  Node *ns = nextSibling(n); +  if (Node *outer = Getattr(c, "nested:outer")) { +    while (ns && outer == Getattr(ns, "nested:outer")) { +      n = ns; +      ns = nextSibling(n); +    } +  } +  if (!ns) { +    set_lastChild(g, c); +  } else { +    set_nextSibling(c, ns); +    set_previousSibling(ns, c); +  } +  set_nextSibling(n, c); +  set_previousSibling(c, n); +} + +void Swig_nested_name_unnamed_c_structs(Node *n) { +  if (!n) +    return; +  if (!classhash) +    classhash = Getattr(n, "classes"); +  Node *c = firstChild(n); +  while (c) { +    Node *next = nextSibling(c); +    if (String *declName = Getattr(c, "nested:unnamed")) { +      if (Node *outer = Getattr(c, "nested:outer")) { +	// generate a name +	String *name = NewStringf("%s_%s", Getattr(outer, "name"), declName); +	Delattr(c, "nested:unnamed"); +	// set the name to the class and symbol table +	Setattr(c, "tdname", name); +	Setattr(c, "name", name); +	Swig_symbol_setscope(Getattr(c, "symtab")); +	Swig_symbol_setscopename(name); +	// now that we have a name - gather base symbols +	if (List *publicBases = Getattr(c, "baselist")) { +	  List *bases = Swig_make_inherit_list(name, publicBases, 0); +	  Swig_inherit_base_symbols(bases); +	  Delete(bases); +	} +	Setattr(classhash, name, c); + +	// Merge the extension into the symbol table +	if (Node *am = Getattr(Swig_extend_hash(), name)) { +	  Swig_extend_merge(c, am); +	  Swig_extend_append_previous(c, am); +	  Delattr(Swig_extend_hash(), name); +	} +	Swig_symbol_popscope(); + +	// process declarations following this type (assign correct new type) +	SwigType *ty = Copy(name); +	Node *decl = nextSibling(c); +	List *declList = NewList(); +	while (decl && Getattr(decl, "nested:unnamedtype") == c) { +	  Setattr(decl, "type", ty); +	  Append(declList, decl); +	  Delattr(decl, "nested:unnamedtype"); +	  SetFlag(decl, "feature:immutable"); +	  add_symbols_c(decl); +	  decl = nextSibling(decl); +	} +	Delete(ty); +	Swig_symbol_setscope(Swig_symbol_global_scope()); +	add_symbols_c(c); + +	Node *ins = create_insert(c); +	insertNodeAfter(c, ins); +	removeNode(c); +	insertNodeAfter(n, c); +	Delete(ins); +	Delattr(c, "nested:outer"); +      } else { +	// global unnamed struct - ignore it and its instances +	SetFlag(c, "feature:ignore"); +	while (next && Getattr(next, "nested:unnamedtype") == c) { +	  SetFlag(next, "feature:ignore"); +	  next = nextSibling(next); +	} +	c = next; +	continue; +      } +    } else if (cparse_cplusplusout) { +      if (Getattr(c, "nested:outer")) { +	Node *ins = create_insert(c, true); +	insertNodeAfter(c, ins); +	Delete(ins); +	Delattr(c, "nested:outer"); +      } +    } +    // process children +    Swig_nested_name_unnamed_c_structs(c); +    c = next; +  } +} + +static void remove_outer_class_reference(Node *n) { +  for (Node *c = firstChild(n); c; c = nextSibling(c)) { +    if (GetFlag(c, "feature:flatnested") || Language::instance()->nestedClassesSupport() == Language::NCS_None) { +      Delattr(c, "nested:outer"); +      remove_outer_class_reference(c); +    } +  } +} + +void Swig_nested_process_classes(Node *n) { +  if (!n) +    return; +  Node *c = firstChild(n); +  while (c) { +    Node *next = nextSibling(c); +    if (!Getattr(c, "templatetype")) { +      if (GetFlag(c, "nested") && (GetFlag(c, "feature:flatnested") || Language::instance()->nestedClassesSupport() == Language::NCS_None)) { +	removeNode(c); +	if (!checkAttribute(c, "access", "public")) +	  SetFlag(c, "feature:ignore"); +	else if (Strcmp(nodeType(n),"extend") == 0 && Strcmp(nodeType(parentNode(n)),"class") == 0) +	  insertNodeAfter(parentNode(n), c); +	else +	  insertNodeAfter(n, c); +      } +      Swig_nested_process_classes(c); +    } +    c = next; +  } +  remove_outer_class_reference(n); +} + diff --git a/contrib/tools/swig/Source/Modules/ocaml.cxx b/contrib/tools/swig/Source/Modules/ocaml.cxx new file mode 100644 index 00000000000..963a0c2d102 --- /dev/null +++ b/contrib/tools/swig/Source/Modules/ocaml.cxx @@ -0,0 +1,1848 @@ +/* -----------------------------------------------------------------------------  + * This file is part of SWIG, which is licensed as a whole under version 3  + * (or any later version) of the GNU General Public License. Some additional + * terms also apply to certain portions of SWIG. The full details of the SWIG + * license and copyrights can be found in the LICENSE and COPYRIGHT files + * included with the SWIG source code as distributed by the SWIG developers + * and at https://www.swig.org/legal.html. + * + * ocaml.cxx + * + * Ocaml language module for SWIG. + * ----------------------------------------------------------------------------- */ + +#include "swigmod.h" +#include <ctype.h> + +static const char *usage = "\ +Ocaml Options (available with -ocaml)\n\ +     -oldvarnames    - Old intermediary method names for variable wrappers\n\ +     -prefix <name>  - Set a prefix <name> to be prepended to all names\n\ +     -suffix <name>  - Deprecated alias for general option -cppext\n\ +     -where          - Emit library location\n\ +\n"; + +static int classmode = 0; +static int in_constructor = 0, in_destructor = 0, in_copyconst = 0; +static int const_enum = 0; +static int static_member_function = 0; +static int generate_sizeof = 0; +static String *prefix = 0; +static const char *ocaml_path = "ocaml"; +static bool old_variable_names = false; +static String *classname = 0; +static String *module = 0; +static String *init_func_def = 0; +static String *f_classtemplate = 0; +static SwigType *name_qualifier_type = 0; + +static Hash *seen_enums = 0; +static Hash *seen_enumvalues = 0; +static Hash *seen_constructors = 0; + +static File *f_header = 0; +static File *f_begin = 0; +static File *f_runtime = 0; +static File *f_wrappers = 0; +static File *f_directors = 0; +static File *f_directors_h = 0; +static File *f_init = 0; +static File *f_mlout = 0; +static File *f_mliout = 0; +static File *f_mlbody = 0; +static File *f_mlibody = 0; +static File *f_mltail = 0; +static File *f_mlitail = 0; +static File *f_enumtypes_type = 0; +static File *f_enumtypes_value = 0; +static File *f_class_ctors = 0; +static File *f_class_ctors_end = 0; +static File *f_enum_to_int = 0; +static File *f_int_to_enum = 0; + +class OCAML:public Language { +public: + +  OCAML() { +    director_prot_ctor_code = NewString(""); +    Printv(director_prot_ctor_code, +	   "if ( $comparison ) { /* subclassed */\n", +	   "  $director_new \n", "} else {\n", "  caml_failwith(\"accessing abstract class or protected constructor\"); \n", "}\n", NIL); +    director_multiple_inheritance = 1; +    director_language = 1; +  } +  +  String *Swig_class_name(Node *n) { +    String *name; +    name = Copy(Getattr(n, "sym:name")); +    return name; +  } + +  void PrintIncludeArg() { +    Printv(stdout, SWIG_LIB, SWIG_FILE_DELIMITER, ocaml_path, "\n", NIL); +  } + +  /* ------------------------------------------------------------ +   * main() +   * ------------------------------------------------------------ */ + +  virtual void main(int argc, char *argv[]) { +    int i; + +    prefix = 0; + +    SWIG_library_directory(ocaml_path); + +    // Look for certain command line options +    for (i = 1; i < argc; i++) { +      if (argv[i]) { +	if (strcmp(argv[i], "-help") == 0) { +	  fputs(usage, stdout); +	  Exit(EXIT_SUCCESS); +	} else if (strcmp(argv[i], "-where") == 0) { +	  PrintIncludeArg(); +	  Exit(EXIT_SUCCESS); +	} else if (strcmp(argv[i], "-prefix") == 0) { +	  if (argv[i + 1]) { +	    prefix = NewString(argv[i + 1]); +	    Swig_mark_arg(i); +	    Swig_mark_arg(i + 1); +	    i++; +	  } else { +	    Swig_arg_error(); +	  } +	} else if (strcmp(argv[i], "-suffix") == 0) { +	  if (argv[i + 1]) { +	    Printf(stderr, "swig: warning: -suffix option deprecated.  SWIG 3.0.4 and later provide a -cppext option which should be used instead.\n"); +	    SWIG_config_cppext(argv[i + 1]); +	    Swig_mark_arg(i); +	    Swig_mark_arg(i + 1); +	    i++; +	  } else +	    Swig_arg_error(); +	} else if (strcmp(argv[i], "-oldvarnames") == 0) { +	  Swig_mark_arg(i); +	  old_variable_names = true; +	} +      } +    } + +    // If a prefix has been specified make sure it ends in a '_' (not actually used!) +    if (prefix) { +      const char *px = Char(prefix); +      if (px[Len(prefix) - 1] != '_') +	Printf(prefix, "_"); +    } else +      prefix = NewString("swig_"); + +    // Add a symbol for this module + +    Preprocessor_define("SWIGOCAML 1", 0); +    // Set name of typemaps + +    SWIG_typemap_lang("ocaml"); + +    // Read in default typemaps */ +    SWIG_config_file("ocaml.i"); +    allow_overloading(); + +  } + +  /* Swig_director_declaration() +   * +   * Generate the full director class declaration, complete with base classes. +   * e.g. "class SwigDirector_myclass : public myclass, public Swig::Director {" +   * +   */ + +  String *Swig_director_declaration(Node *n) { +    String *classname = Swig_class_name(n); +    String *directorname = NewStringf("SwigDirector_%s", classname); +    String *base = Getattr(n, "classtype"); +    String *declaration = Swig_class_declaration(n, directorname); +    Printf(declaration, " : public %s, public Swig::Director {\n", base); +    Delete(classname); +    Delete(directorname); +    return declaration; +  } + +  void emitBanner(File *f) { +    Printf(f, "(* ----------------------------------------------------------------------------\n"); +    Swig_banner_target_lang(f, " *"); +    Printf(f, " * ---------------------------------------------------------------------------- *)\n\n"); +  } + +  /* ------------------------------------------------------------ +   * top() +   * +   * Recognize the %module, and capture the module name. +   * Create the default enum cases. +   * Set up the named outputs: +   * +   *  init +   *  ml +   *  mli +   *  wrapper +   *  header +   *  runtime +   *  directors +   *  directors_h +   * ------------------------------------------------------------ */ + +  virtual int top(Node *n) { +    /* Set comparison with none for ConstructorToFunction */ +    setSubclassInstanceCheck(NewString("caml_list_nth(args,0) != Val_unit")); + +    /* check if directors are enabled for this module.  note: this  +     * is a "master" switch, without which no director code will be +     * emitted.  %feature("director") statements are also required +     * to enable directors for individual classes or methods. +     * +     * use %module(directors="1") modulename at the start of the  +     * interface file to enable director generation. +     */ +    String *mod_docstring = NULL; +    { +      Node *module = Getattr(n, "module"); +      if (module) { +	Node *options = Getattr(module, "options"); +	if (options) { +	  if (Getattr(options, "directors")) { +	    allow_directors(); +	  } +	  if (Getattr(options, "dirprot")) { +	    allow_dirprot(); +	  } +	  if (Getattr(options, "sizeof")) { +	    generate_sizeof = 1; +	  } +	  mod_docstring = Getattr(options, "docstring"); +	} +      } +    } + +    /* Initialize all of the output files */ +    String *outfile = Getattr(n, "outfile"); + +    f_begin = NewFile(outfile, "w", SWIG_output_files()); +    if (!f_begin) { +      FileErrorDisplay(outfile); +      Exit(EXIT_FAILURE); +    } +    f_runtime = NewString(""); +    f_init = NewString(""); +    f_header = NewString(""); +    f_wrappers = NewString(""); +    f_directors = NewString(""); +    f_directors_h = NewString(""); +    f_enumtypes_type = NewString(""); +    f_enumtypes_value = NewString(""); +    init_func_def = NewString(""); +    f_mlbody = NewString(""); +    f_mlibody = NewString(""); +    f_mltail = NewString(""); +    f_mlitail = NewString(""); +    f_class_ctors = NewString(""); +    f_class_ctors_end = NewString(""); +    f_enum_to_int = NewString(""); +    f_int_to_enum = NewString(""); +    f_classtemplate = NewString(""); + +    module = Getattr(n, "name"); + +    seen_constructors = NewHash(); +    seen_enums = NewHash(); +    seen_enumvalues = NewHash(); + +    /* Register file targets with the SWIG file handler */ +    Swig_register_filebyname("init", init_func_def); +    Swig_register_filebyname("header", f_header); +    Swig_register_filebyname("wrapper", f_wrappers); +    Swig_register_filebyname("begin", f_begin); +    Swig_register_filebyname("runtime", f_runtime); +    Swig_register_filebyname("mli", f_mlibody); +    Swig_register_filebyname("ml", f_mlbody); +    Swig_register_filebyname("mlitail", f_mlitail); +    Swig_register_filebyname("mltail", f_mltail); +    Swig_register_filebyname("director", f_directors); +    Swig_register_filebyname("director_h", f_directors_h); +    Swig_register_filebyname("classtemplate", f_classtemplate); +    Swig_register_filebyname("class_ctors", f_class_ctors); + +    if (old_variable_names) { +      Swig_name_register("set", "%n%v__set__"); +      Swig_name_register("get", "%n%v__get__"); +    } + +    Swig_banner(f_begin); + +    Swig_obligatory_macros(f_runtime, "OCAML"); + +    Printf(f_runtime, "#define SWIG_MODULE \"%s\"\n", module); +    /* Module name */ +    Printf(f_mlbody, "let module_name = \"%s\"\n", module); +    Printf(f_mlibody, "val module_name : string\n"); +    Printf(f_enum_to_int, +	   "let enum_to_int x (v : c_obj) =\n" +	   "   match v with\n" +	   "     C_enum _y ->\n" +	   "     (let y = _y in match (x : c_enum_type) with\n" +	   "       `unknown -> " "         (match y with\n" "           `Int x -> (Swig.C_int x)\n" "           | _ -> raise (LabelNotFromThisEnum v))\n"); + +    Printf(f_int_to_enum, "let int_to_enum x y =\n" "    match (x : c_enum_type) with\n" "      `unknown -> C_enum (`Int y)\n"); + +    if (directorsEnabled()) { +      Printf(f_runtime, "#define SWIG_DIRECTORS\n"); +    } + +    Printf(f_runtime, "\n"); + +    /* Produce the enum_to_int and int_to_enum functions */ + +    Printf(f_enumtypes_type, "open Swig\n" "type c_enum_type = [ \n  `unknown\n"); +    Printf(f_enumtypes_value, "type c_enum_value = [ \n  `Int of int\n"); +    String *mlfile = NewString(""); +    String *mlifile = NewString(""); + +    Printv(mlfile, module, ".ml", NIL); +    Printv(mlifile, module, ".mli", NIL); + +    String *mlfilen = NewStringf("%s%s", SWIG_output_directory(), mlfile); +    if ((f_mlout = NewFile(mlfilen, "w", SWIG_output_files())) == 0) { +      FileErrorDisplay(mlfilen); +      Exit(EXIT_FAILURE); +    } +    String *mlifilen = NewStringf("%s%s", SWIG_output_directory(), mlifile); +    if ((f_mliout = NewFile(mlifilen, "w", SWIG_output_files())) == 0) { +      FileErrorDisplay(mlifilen); +      Exit(EXIT_FAILURE); +    } +    emitBanner(f_mlout); +    emitBanner(f_mliout); + +    Language::top(n); + +    if (mod_docstring) { +      if (Len(mod_docstring)) { +	Printv(f_mliout, "(** ", mod_docstring, " *)\n", NIL); +      } +      Delete(mod_docstring); +      mod_docstring = NULL; +    } + +    Printf(f_enum_to_int, ") | _ -> (C_int (get_int v))\n" "let _ = Callback.register \"%s_enum_to_int\" enum_to_int\n", module); +    Printf(f_mlibody, "val enum_to_int : c_enum_type -> c_obj -> Swig.c_obj\n"); + +    Printf(f_int_to_enum, "let _ = Callback.register \"%s_int_to_enum\" int_to_enum\n", module); +    Printf(f_mlibody, "val int_to_enum : c_enum_type -> int -> c_obj\n"); +    Printf(f_init, "#define SWIG_init f_%s_init\n" "%s" "}\n", module, init_func_def); +    Printf(f_mlbody, "external f_init : unit -> unit = \"f_%s_init\" ;;\n" "let _ = f_init ()\n", module); +    Printf(f_enumtypes_type, "]\n"); +    Printf(f_enumtypes_value, "]\n\n" "type c_obj = c_enum_value c_obj_t\n"); + +    if (directorsEnabled()) { +      // Insert director runtime into the f_runtime file (make it occur before %header section) +      Swig_insert_file("director_common.swg", f_runtime); +      Swig_insert_file("director.swg", f_runtime); +    } + +    SwigType_emit_type_table(f_runtime, f_wrappers); +    /* Close all of the files */ +    Dump(f_runtime, f_begin); +    Dump(f_directors_h, f_header); +    Dump(f_header, f_begin); +    Dump(f_directors, f_wrappers); +    Dump(f_wrappers, f_begin); +    Wrapper_pretty_print(f_init, f_begin); +    Delete(f_header); +    Delete(f_wrappers); +    Delete(f_init); +    Delete(f_runtime); +    Delete(f_begin); + +    Dump(f_enumtypes_type, f_mlout); +    Dump(f_enumtypes_value, f_mlout); +    Dump(f_mlbody, f_mlout); +    Dump(f_enum_to_int, f_mlout); +    Dump(f_int_to_enum, f_mlout); +    Delete(f_int_to_enum); +    Delete(f_enum_to_int); +    Dump(f_class_ctors, f_mlout); +    Dump(f_class_ctors_end, f_mlout); +    Dump(f_mltail, f_mlout); +    Delete(f_mlout); + +    Dump(f_enumtypes_type, f_mliout); +    Dump(f_enumtypes_value, f_mliout); +    Dump(f_mlibody, f_mliout); +    Dump(f_mlitail, f_mliout); +    Delete(f_mliout); + +    return SWIG_OK; +  } + +  /* Produce an error for the given type */ +  void throw_unhandled_ocaml_type_error(SwigType *d, const char *types) { +    Swig_warning(WARN_TYPEMAP_UNDEF, input_file, line_number, "Unable to handle type %s (%s).\n", SwigType_str(d, 0), types); +  } + +  /* Return true iff T is a pointer type */ +  int +   is_a_pointer(SwigType *t) { +    return SwigType_ispointer(SwigType_typedef_resolve_all(t)); +  } + +  /* +   * Delete one reference from a given type. +   */ + +  void oc_SwigType_del_reference(SwigType *t) { +    if (SwigType_isqualifier(t)) { +      SwigType_del_qualifier(t); +    } +    SwigType_del_reference(t); +  } + +  void oc_SwigType_del_array(SwigType *t) { +    if (SwigType_isqualifier(t)) { +      SwigType_del_qualifier(t); +    } +    if (SwigType_isarray(t)) { +      SwigType_del_array(t); +    } +  } + +  /*  +   * Return true iff T is a reference type  +   */ + +  int +   is_a_reference(SwigType *t) { +    return SwigType_isreference(SwigType_typedef_resolve_all(t)); +  } + +  int +   is_an_array(SwigType *t) { +    return SwigType_isarray(SwigType_typedef_resolve_all(t)); +  } + +  virtual int membervariableHandler(Node *n) { +    String *symname = Getattr(n, "sym:name"); +    Language::membervariableHandler(n); + +    String *mname = Swig_name_member(NSPACE_TODO, classname, symname); +    String *getname = Swig_name_get(NSPACE_TODO, mname); +    String *mangled_getname = mangleNameForCaml(getname); +    Delete(getname); + +    if (!GetFlag(n, "feature:immutable")) { +      String *setname = Swig_name_set(NSPACE_TODO, mname); +      String *mangled_setname = mangleNameForCaml(setname); +      Delete(setname); +      Printf(f_class_ctors, "    \"[%s]\", (fun args -> " "if args = (C_list [ raw_ptr ]) then _%s args else _%s args) ;\n", symname, mangled_getname, mangled_setname); +      Delete(mangled_setname); +    } else { +      Printf(f_class_ctors, "    \"[%s]\", (fun args -> " "if args = (C_list [ raw_ptr ]) then _%s args else C_void) ;\n", symname, mangled_getname); +    } +    Delete(mangled_getname); +    Delete(mname); +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * functionWrapper() +   * Create a function declaration and register it with the interpreter. +   * ------------------------------------------------------------ */ + +  virtual int functionWrapper(Node *n) { +    char *iname = GetChar(n, "sym:name"); +    SwigType *d = Getattr(n, "type"); +    String *return_type_normalized = normalizeTemplatedClassName(d); +    ParmList *l = Getattr(n, "parms"); +    int director_method = 0; +    Parm *p; + +    Wrapper *f = NewWrapper(); +    String *proc_name = NewString(""); +    String *target = NewString(""); +    String *arg = NewString(""); +    String *cleanup = NewString(""); +    String *outarg = NewString(""); +    String *build = NewString(""); +    String *tm; +    int i = 0; +    int numargs; +    int numreq; +    int newobj = GetFlag(n, "feature:new"); +    String *nodeType = Getattr(n, "nodeType"); +    int destructor = (!Cmp(nodeType, "destructor")); +    String *overname = 0; +    bool isOverloaded = Getattr(n, "sym:overloaded") ? true : false; +    // For overloaded functions, only the dispatch function needs to be exposed in the ml and mli files. +    bool expose_func = !isOverloaded || !Getattr(n, "sym:nextSibling"); + +    // Make a wrapper name for this +    String *wname = Swig_name_wrapper(iname); +    if (isOverloaded) { +      overname = Getattr(n, "sym:overname"); +    } else { +      if (!addSymbol(iname, n)) { +        DelWrapper(f); +	return SWIG_ERROR; +      } +    } +    if (overname) { +      Append(wname, overname); +    } +    /* Do this to disambiguate functions emitted from different modules */ +    Append(wname, module); + +    Setattr(n, "wrap:name", wname); + +    // Build the name for Scheme. +    Printv(proc_name, "_", iname, NIL); +    String *mangled_name = mangleNameForCaml(proc_name); + +    if (classmode && in_constructor && expose_func) { // Emit constructor for object +      String *mangled_name_nounder = NewString((char *) (Char(mangled_name)) + 1); +      Printf(f_class_ctors_end, "let %s clst = _%s clst\n", mangled_name_nounder, mangled_name_nounder); +      Printf(f_mlibody, "val %s : c_obj -> c_obj\n", mangled_name_nounder); +      Delete(mangled_name_nounder); +    } else if (classmode && in_destructor) { +      Printf(f_class_ctors, "    \"~\", %s ;\n", mangled_name); +    } else if (classmode && !in_constructor && !in_destructor && !static_member_function && +	    !Getattr(n, "membervariableHandler:sym:name") && expose_func) { +      String *opname = Copy(Getattr(n, "memberfunctionHandler:sym:name")); + +      Replaceall(opname, "operator ", ""); +      Printf(f_class_ctors, "    \"%s\", %s ;\n", opname, mangled_name); +      Delete(opname); +    } + +    if (classmode && in_constructor) { +      Setattr(seen_constructors, mangled_name, "true"); +    } +    // writing the function wrapper function +    Printv(f->def, "SWIGEXT CAML_VALUE ", wname, " (", NIL); +    Printv(f->def, "CAML_VALUE args", NIL); +    Printv(f->def, ")\n{", NIL); + +    /* Define the scheme name in C. This define is used by several +       macros. */ +    //Printv(f->def, "#define FUNC_NAME \"", mangled_name, "\"", NIL); + +    // adds local variables +    Wrapper_add_local(f, "args", "CAMLparam1(args)"); +    Wrapper_add_local(f, "ret", "SWIG_CAMLlocal2(swig_result,rv)"); +    d = SwigType_typedef_qualified(d); +    emit_parameter_variables(l, f); + +    /* Attach the standard typemaps */ +    emit_attach_parmmaps(l, f); +    Setattr(n, "wrap:parms", l); + +    numargs = emit_num_arguments(l); +    numreq = emit_num_required(l); +    if (!isOverloaded) { +      if (numargs > 0) { +	if (numreq > 0) { +	  Printf(f->code, "if (caml_list_length(args) < %d || caml_list_length(args) > %d) {\n", numreq, numargs); +	} else { +	  Printf(f->code, "if (caml_list_length(args) > %d) {\n", numargs); +	} +	Printf(f->code, "caml_invalid_argument(\"Incorrect number of arguments passed to '%s'\");\n}\n", iname); +      } else { +	Printf(f->code, "if (caml_list_length(args) > 0) caml_invalid_argument(\"'%s' takes no arguments\");\n", iname); +      } +    } +    Printf(f->code, "swig_result = Val_unit;\n"); + +    // Now write code to extract the parameters (this is super ugly) + +    for (i = 0, p = l; i < numargs; i++) { +      /* Skip ignored arguments */ +      while (checkAttribute(p, "tmap:in:numinputs", "0")) { +	p = Getattr(p, "tmap:in:next"); +      } + +      SwigType *pt = Getattr(p, "type"); +      String *ln = Getattr(p, "lname"); +      pt = SwigType_typedef_qualified(pt); + +      // Produce names of source and target +      Clear(target); +      Clear(arg); +      String *source = NewStringf("caml_list_nth(args,%d)", i); +      Printf(target, "%s", ln); +      Printv(arg, Getattr(p, "name"), NIL); + +      if (i >= numreq) { +	Printf(f->code, "if (caml_list_length(args) > %d) {\n", i); +      } +      // Handle parameter types. +      if ((tm = Getattr(p, "tmap:in"))) { +	Replaceall(tm, "$input", source); +	Setattr(p, "emit:input", source); +	Printv(f->code, tm, "\n", NIL); +	p = Getattr(p, "tmap:in:next"); +      } else { +	// no typemap found +	// check if typedef and resolve +	throw_unhandled_ocaml_type_error(pt, "in"); +	p = nextSibling(p); +      } +      if (i >= numreq) { +	Printf(f->code, "}\n"); +      } +      Delete(source); +    } + +    /* Insert constraint checking code */ +    for (p = l; p;) { +      if ((tm = Getattr(p, "tmap:check"))) { +	Printv(f->code, tm, "\n", NIL); +	p = Getattr(p, "tmap:check:next"); +      } else { +	p = nextSibling(p); +      } +    } + +    // Pass output arguments back to the caller. + +    for (p = l; p;) { +      if ((tm = Getattr(p, "tmap:argout"))) { +	Replaceall(tm, "$arg", Getattr(p, "emit:input")); +	Replaceall(tm, "$input", Getattr(p, "emit:input")); +	Replaceall(tm, "$ntype", normalizeTemplatedClassName(Getattr(p, "type"))); +	Printv(outarg, tm, "\n", NIL); +	p = Getattr(p, "tmap:argout:next"); +      } else { +	p = nextSibling(p); +      } +    } + +    // Free up any memory allocated for the arguments. + +    /* Insert cleanup code */ +    for (p = l; p;) { +      if ((tm = Getattr(p, "tmap:freearg"))) { +	Printv(cleanup, tm, "\n", NIL); +	p = Getattr(p, "tmap:freearg:next"); +      } else { +	p = nextSibling(p); +      } +    } + +    /* if the object is a director, and the method call originated from its +     * underlying ocaml object, resolve the call by going up the c++  +     * inheritance chain.  otherwise try to resolve the method in ocaml. +     * without this check an infinite loop is set up between the director and +     * shadow class method calls. +     */ + +    // NOTE: this code should only be inserted if this class is the +    // base class of a director class.  however, in general we haven't +    // yet analyzed all classes derived from this one to see if they are +    // directors.  furthermore, this class may be used as the base of +    // a director class defined in a completely different module at a +    // later time, so this test must be included whether or not directorbase +    // is true.  we do skip this code if directors have not been enabled +    // at the command line to preserve source-level compatibility with +    // non-polymorphic swig.  also, if this wrapper is for a smart-pointer +    // method, there is no need to perform the test since the calling object +    // (the smart-pointer) and the director object (the "pointee") are +    // distinct. + +    director_method = is_member_director(n) && !is_smart_pointer() && !destructor; +    if (director_method) { +      Wrapper_add_local(f, "director", "Swig::Director *director = 0"); +      Printf(f->code, "director = dynamic_cast<Swig::Director *>(arg1);\n"); +      Wrapper_add_local(f, "upcall", "bool upcall = false"); +      Append(f->code, "upcall = (director);\n"); +    } + +    // Now write code to make the function call +    Swig_director_emit_dynamic_cast(n, f); +    String *actioncode = emit_action(n); + +    if ((tm = Swig_typemap_lookup_out("out", n, Swig_cresult_name(), f, actioncode))) { +      Replaceall(tm, "$result", "rv"); +      Replaceall(tm, "$ntype", return_type_normalized); +      Printv(f->code, tm, "\n", NIL); +    } else { +      throw_unhandled_ocaml_type_error(d, "out"); +    } +    emit_return_variable(n, d, f); + +    // Dump the argument output code +    Printv(f->code, Char(outarg), NIL); + +    // Dump the argument cleanup code +    Printv(f->code, Char(cleanup), NIL); + +    // Look for any remaining cleanup + +    if (GetFlag(n, "feature:new")) { +      if ((tm = Swig_typemap_lookup("newfree", n, Swig_cresult_name(), 0))) { +	Printv(f->code, tm, "\n", NIL); +      } +    } + +    /* See if there is any return cleanup code */ +    if ((tm = Swig_typemap_lookup("ret", n, Swig_cresult_name(), 0))) { +      Printf(f->code, "%s\n", tm); +      Delete(tm); +    } + +    // Free any memory allocated by the function being wrapped.. + +    if ((tm = Swig_typemap_lookup("swig_result", n, Swig_cresult_name(), 0))) { +      Printv(f->code, tm, "\n", NIL); +    } +    // Wrap things up (in a manner of speaking) + +    Printv(f->code, tab4, "swig_result = caml_list_append(swig_result,rv);\n", NIL); +    Printv(f->code, tab4, "CAMLreturn(swig_result);\n", NIL); +    Printv(f->code, "}\n", NIL); + +    /* Substitute the function name */ +    Replaceall(f->code, "$symname", iname); + +    Wrapper_print(f, f_wrappers); + +    if (isOverloaded) { +      if (!Getattr(n, "sym:nextSibling")) { +	int maxargs; +	Wrapper *df = NewWrapper(); +	String *dispatch = Swig_overload_dispatch(n, +						  "free(argv);\n" "CAMLreturn(%s(args));\n", +						  &maxargs); + +	Wrapper_add_local(df, "argv", "CAML_VALUE *argv"); + +	/* Undifferentiate name .. this is the dispatch function */ +	wname = Swig_name_wrapper(iname); +	/* Do this to disambiguate functions emitted from different +	 * modules */ +	Append(wname, module); + +	Printv(df->def, +	       "SWIGEXT CAML_VALUE ", wname, "(CAML_VALUE args) {\n" "  CAMLparam1(args);\n" "  int i;\n" "  int argc = caml_list_length(args);\n", NIL); +	Printv(df->code, +	       "argv = (CAML_VALUE *)malloc( argc * sizeof( CAML_VALUE ) );\n" +	       "for( i = 0; i < argc; i++ ) {\n" "  argv[i] = caml_list_nth(args,i);\n" "}\n", NIL); +	Printv(df->code, dispatch, "\nfree(argv);\n", NIL); +	Node *sibl = n; +	while (Getattr(sibl, "sym:previousSibling")) +	  sibl = Getattr(sibl, "sym:previousSibling"); +	String *protoTypes = NewString(""); +	do { +	  String *fulldecl = Swig_name_decl(sibl); +	  Printf(protoTypes, "\n\"    %s\\n\"", fulldecl); +	  Delete(fulldecl); +	} while ((sibl = Getattr(sibl, "sym:nextSibling"))); +	Printf(df->code, "caml_failwith(\"Wrong number or type of arguments for overloaded function '%s'.\\n\"" +	       "\n\"  Possible C/C++ prototypes are:\\n\"%s);\n", iname, protoTypes); +	Delete(protoTypes); +	Printv(df->code, "}\n", NIL); +	Wrapper_print(df, f_wrappers); + +	DelWrapper(df); +	Delete(dispatch); +      } +    } + +    if (expose_func) { +      Printf(f_mlbody, "external %s_f : c_obj list -> c_obj list = \"%s\" ;;\n", mangled_name, wname); +      Printf(f_mlbody, "let %s arg = match %s_f (%s(fnhelper arg)) with\n", mangled_name, mangled_name, +	     in_constructor && Swig_directorclass(getCurrentClass()) ? "director_core_helper " : ""); +      Printf(f_mlbody, "  [] -> C_void\n" +	     "| [x] -> (if %s then Gc.finalise \n" +	     "  (fun x -> ignore ((invoke x) \"~\" C_void)) x) ; x\n" +	     "| lst -> C_list lst ;;\n", newobj ? "true" : "false"); +    } + +    if ((!classmode || in_constructor || in_destructor || static_member_function) && expose_func) +      Printf(f_mlibody, "val %s : c_obj -> c_obj\n", mangled_name); + +    Delete(proc_name); +    Delete(target); +    Delete(arg); +    Delete(outarg); +    Delete(cleanup); +    Delete(build); +    DelWrapper(f); +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * variableWrapper() +   * +   * Create a link to a C variable. +   * This creates a single function _wrap_varname(). +   * This function takes a single optional argument.   If supplied, it means +   * we are setting this variable to some value.  If omitted, it means we are +   * simply evaluating this variable.  We return the value of the variable +   * in both cases. +   * +   * symname is the name of the variable with respect to C.  This  +   * may need to differ from the original name in the case of enums. +   * enumvname is the name of the variable with respect to ocaml.  This +   * will vary if the variable has been renamed. +   * ------------------------------------------------------------ */ + +  virtual int variableWrapper(Node *n) { +    char *name = GetChar(n, "feature:symname"); +    String *iname = Getattr(n, "feature:enumvname"); +    String *mname = mangleNameForCaml(iname); +    SwigType *t = Getattr(n, "type"); + +    String *proc_name = NewString(""); +    String *tm; +    Wrapper *f; + +    if (!name) { +      name = GetChar(n, "name"); +    } + +    if (!iname) { +      iname = Getattr(n, "sym:name"); +      mname = mangleNameForCaml(NewString(iname)); +    } + +    if (!iname || !addSymbol(iname, n)) +      return SWIG_ERROR; + +    f = NewWrapper(); + +    // evaluation function names +    String *var_name = Swig_name_wrapper(iname); + +    // Build the name for OCaml. +    Printv(proc_name, iname, NIL); +    Setattr(n, "wrap:name", proc_name); + +    Printf(f->def, "SWIGEXT CAML_VALUE %s(CAML_VALUE args) {\n", var_name); +    // Printv(f->def, "#define FUNC_NAME \"", proc_name, "\"", NIL); + +    Wrapper_add_local(f, "args", "CAMLparam1(args)"); +    Wrapper_add_local(f, "swig_result", "SWIG_CAMLlocal1(swig_result)"); +    Printf(f->code, "swig_result = Val_unit;\n"); + +    if (!GetFlag(n, "feature:immutable")) { +      /* Check for a setting of the variable value */ +      Printf(f->code, "if (args != Val_int(0)) {\n"); +      if ((tm = Swig_typemap_lookup("varin", n, name, 0))) { +	Replaceall(tm, "$input", "args"); +	emit_action_code(n, f->code, tm); +      } else if ((tm = Swig_typemap_lookup("in", n, name, 0))) { +	Replaceall(tm, "$input", "args"); +	emit_action_code(n, f->code, tm); +      } else { +	throw_unhandled_ocaml_type_error(t, "varin/in"); +      } +      Printf(f->code, "}\n"); +    } +    // Now return the value of the variable (regardless +    // of evaluating or setting) + +    if ((tm = Swig_typemap_lookup("varout", n, name, 0))) { +      Replaceall(tm, "$result", "swig_result"); +      emit_action_code(n, f->code, tm); +    } else if ((tm = Swig_typemap_lookup("out", n, name, 0))) { +      Replaceall(tm, "$result", "swig_result"); +      emit_action_code(n, f->code, tm); +    } else { +      throw_unhandled_ocaml_type_error(t, "varout/out"); +    } + +    Printf(f->code, "\nCAMLreturn(swig_result);\n"); +    Printf(f->code, "}\n"); + +    Wrapper_print(f, f_wrappers); + +    // Now add symbol to the Ocaml interpreter + +    if (GetFlag(n, "feature:immutable")) { +      Printf(f_mlbody, "external _%s : c_obj -> Swig.c_obj = \"%s\" \n", mname, var_name); +      Printf(f_mlibody, "val _%s : c_obj -> Swig.c_obj\n", iname); +      if (const_enum) { +	Printf(f_enum_to_int, " | `%s -> _%s C_void\n", mname, mname); +	Printf(f_int_to_enum, " if y = (get_int (_%s C_void)) then `%s else\n", mname, mname); +      } +    } else { +      Printf(f_mlbody, "external _%s : c_obj -> c_obj = \"%s\"\n", mname, var_name); +      Printf(f_mlibody, "external _%s : c_obj -> c_obj = \"%s\"\n", mname, var_name); +    } + +    Delete(var_name); +    Delete(proc_name); +    DelWrapper(f); +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * staticmemberfunctionHandler -- +   * Overridden to set static_member_function  +   * ------------------------------------------------------------ */ + +  virtual int staticmemberfunctionHandler(Node *n) { +    static_member_function = 1; +    Language::staticmemberfunctionHandler(n); +    static_member_function = 0; +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * constantWrapper() +   * +   * The one trick here is that we have to make sure we rename the +   * constant to something useful that doesn't collide with the +   * original if any exists. +   * ------------------------------------------------------------ */ + +  virtual int constantWrapper(Node *n) { +    String *name = Getattr(n, "feature:symname"); +    SwigType *type = Getattr(n, "type"); +    String *rawval = Getattr(n, "rawval"); +    String *value = rawval ? rawval : Getattr(n, "value"); +    SwigType *qname = Getattr(n, "qualified:name"); + +    if (qname) +      value = qname; + +    if (!name) { +      name = mangleNameForCaml(Getattr(n, "name")); +      Insert(name, 0, "_swig_wrap_"); +      Setattr(n, "feature:symname", name); +    } +    // See if there's a typemap + +    // Create variable and assign it a value +    Printf(f_header, "static %s = %s;\n", SwigType_str(type, name), value); +    SetFlag(n, "feature:immutable"); +    variableWrapper(n); +    return SWIG_OK; +  } + +  int constructorHandler(Node *n) { +    int ret; + +    in_constructor = 1; +    ret = Language::constructorHandler(n); +    in_constructor = 0; + +    return ret; +  } + +  /* destructorHandler: +   * Turn on destructor flag to inform decisions in functionWrapper +   */ + +  int destructorHandler(Node *n) { +    int ret; + +    in_destructor = 1; +    ret = Language::destructorHandler(n); +    in_destructor = 0; + +    return ret; +  } + +  /* copyconstructorHandler: +   * Turn on constructor and copyconstructor flags for functionWrapper +   */ + +  int copyconstructorHandler(Node *n) { +    int ret; + +    in_copyconst = 1; +    in_constructor = 1; +    ret = Language::copyconstructorHandler(n); +    in_constructor = 0; +    in_copyconst = 0; + +    return ret; +  } + +    /** +     * A simple, somewhat general purpose function for writing to multiple +     * streams from a source template.  This allows the user to define the +     * class definition in ways different from the one I have here if they +     * want to.  It will also make the class definition system easier to +     * fiddle with when I want to change methods, etc. +     */ + +  void Multiwrite(String *s) { +    char *find_marker = strstr(Char(s), "(*Stream:"); +    while (find_marker) { +      char *next = strstr(find_marker, "*)"); +      find_marker += strlen("(*Stream:"); + +      if (next) { +	int num_chars = (int)(next - find_marker); +	String *stream_name = NewString(find_marker); +	Delslice(stream_name, num_chars, Len(stream_name)); +	File *fout = Swig_filebyname(stream_name); +	if (fout) { +	  next += strlen("*)"); +	  char *following = strstr(next, "(*Stream:"); +	  find_marker = following; +	  if (!following) +	    following = next + strlen(next); +	  String *chunk = NewString(next); +	  Delslice(chunk, (int)(following - next), Len(chunk)); +	  Printv(fout, chunk, NIL); +	} +      } +    } +  } + +  bool isSimpleType(String *name) { +    char *ch = Char(name); + +    return !(strchr(ch, '(') || strchr(ch, '<') || strchr(ch, ')') || strchr(ch, '>')); +  } + +  /* We accept all chars in identifiers because we use strings to index +   * them. */ +  int validIdentifier(String *name) { +    return Len(name) > 0 ? 1 : 0; +  } + +  /* classHandler +   *  +   * Create a "class" definition for ocaml.  I thought quite a bit about +   * how I should do this part of it, and arrived here, using a function +   * invocation to select a method, and dispatch.  This can obviously be +   * done better, but I can't see how, given that I want to support  +   * overloaded methods, out parameters, and operators. +   * +   * I needed a system that would do this: +   * +   *  a Be able to call these methods: +   *   int foo( int x ); +   *   float foo( int x, int &out ); +   * +   *  b Be typeable, even in the presence of mutually dependent classes. +   * +   *  c Support some form of operator invocation. +   * +   * (c) I chose strings for the method names so that "+=" would be a +   * valid method name, and the somewhat natural << (invoke x) "+=" y >> +   * would work. +   * +   * (a) (b) Since the c_obj type exists, it's easy to return C_int in one +   * case and C_list [ C_float ; C_int ] in the other.  This makes tricky +   * problems with out parameters disappear; they're simply appended to the +   * return list. +   * +   * (b) Since every item that comes from C++ is the same type, there is no +   * problem with the following: +   * +   * class Foo; +   * class Bar { Foo *toFoo(); } +   * class Foo { Bar *toBar(); } +   * +   * Since the Objective caml types of Foo and Bar are the same.  Now that +   * I correctly incorporate SWIG's typechecking, this isn't a big deal. +   * +   * The class is in the form of a function returning a c_obj.  The c_obj +   * is a C_obj containing a function which invokes a method on the +   * underlying object given its type. +   * +   * The name emitted here is normalized before being sent to +   * Callback.register, because we need this string to look up properly +   * when the typemap passes the descriptor string.  I've been considering +   * some, possibly more forgiving method that would do some transformations +   * on the $descriptor in order to find a potential match.  This is for +   * later. +   * +   * Important things to note: +   * +   * We rely on exception handling (BadMethodName) in order to call an +   * ancestor.  This can be improved. +   * +   * The method used to get :classof could be improved to look at the type +   * info that the base pointer contains.  It's really an error to have a +   * SWIG-generated object that does not contain type info, since the +   * existence of the object means that SWIG knows the type. +   * +   * :parents could use :classof to tell what class it is and make a better +   * decision.  This could be nice, (i.e. provide a run-time graph of C++ +   * classes represented);. +   * +   * I can't think of a more elegant way of converting a C_obj fun to a +   * pointer than "operator &"...  +   * +   * Added a 'sizeof' that will allow you to do the expected thing. +   * This should help users to fill buffer structs and the like (as is +   * typical in windows-styled code).  It's only enabled if you give +   * %feature(sizeof) and then, only for simple types. +   * +   * Overall, carrying the list of methods and base classes has worked well. +   * It allows me to give the Ocaml user introspection over their objects. +   */ + +  int classHandler(Node *n) { +    String *name = Getattr(n, "name"); +    classname = Getattr(n, "sym:name"); + +    if (!name) +      return SWIG_OK; + +    String *mangled_name = mangleNameForCaml(name); +    String *this_class_def = NewString(f_classtemplate); +    String *name_normalized = normalizeTemplatedClassName(name); +    String *old_class_ctors = f_class_ctors; +    String *base_classes = NewString(""); +    f_class_ctors = NewString(""); +    bool sizeof_feature = generate_sizeof && isSimpleType(name); + + +    classmode = true; +    int rv = Language::classHandler(n); +    classmode = false; + +    if (sizeof_feature) { +      Printf(f_wrappers, +	     "SWIGEXT CAML_VALUE _wrap_%s_sizeof( CAML_VALUE args ) {\n" +	     "    CAMLparam1(args);\n" "    CAMLreturn(Val_int(sizeof(%s)));\n" "}\n", mangled_name, name_normalized); + +      Printf(f_mlbody, "external __%s_sizeof : unit -> int = " "\"_wrap_%s_sizeof\"\n", mangled_name, mangled_name); +    } + + +    /* Insert sizeof operator for concrete classes */ +    if (sizeof_feature) { +      Printv(f_class_ctors, "\"sizeof\" , (fun args -> C_int (__", mangled_name, "_sizeof ())) ;\n", NIL); +    } +    /* Handle up-casts in a nice way */ +    List *baselist = Getattr(n, "bases"); +    if (baselist && Len(baselist)) { +      Iterator b; +      b = First(baselist); +      while (b.item) { +	String *bname = Getattr(b.item, "name"); +	if (bname) { +	  String *base_create = NewString(""); +	  Printv(base_create, "(create_class \"", bname, "\")", NIL); +	  Printv(f_class_ctors, "   \"::", bname, "\", (fun args -> ", base_create, " args) ;\n", NIL); +	  Printv(base_classes, base_create, " ;\n", NIL); +	} +	b = Next(b); +      } +    } + +    Replaceall(this_class_def, "$classname", mangled_name); +    Replaceall(this_class_def, "$normalized", name_normalized); +    Replaceall(this_class_def, "$realname", name); +    Replaceall(this_class_def, "$baselist", base_classes); +    Replaceall(this_class_def, "$classbody", f_class_ctors); + +    Delete(f_class_ctors); +    f_class_ctors = old_class_ctors; + +    // Actually write out the class definition + +    Multiwrite(this_class_def); + +    Setattr(n, "ocaml:ctor", mangled_name); + +    return rv; +  } + +  String *normalizeTemplatedClassName(String *name) { +    String *name_normalized = SwigType_typedef_resolve_all(name); +    bool took_action; + +    do { +      took_action = false; + +      if (is_a_pointer(name_normalized)) { +	SwigType_del_pointer(name_normalized); +	took_action = true; +      } + +      if (is_a_reference(name_normalized)) { +	oc_SwigType_del_reference(name_normalized); +	took_action = true; +      } + +      if (is_an_array(name_normalized)) { +	oc_SwigType_del_array(name_normalized); +	took_action = true; +      } +    } while (took_action); + +    return SwigType_str(name_normalized, 0); +  } + +  /* +   * Produce the symbol name that ocaml will use when referring to the  +   * target item.  I wonder if there's a better way to do this: +   * +   * I shudder to think about doing it with a hash lookup, but that would +   * make a couple of things easier: +   */ + +  String *mangleNameForCaml(String *s) { +    String *out = Copy(s); +    Replaceall(out, " ", "_xx"); +    Replaceall(out, "::", "_xx"); +    Replaceall(out, ",", "_x"); +    Replaceall(out, "+", "_xx_plus"); +    Replaceall(out, "-", "_xx_minus"); +    Replaceall(out, "<", "_xx_ldbrace"); +    Replaceall(out, ">", "_xx_rdbrace"); +    Replaceall(out, "!", "_xx_not"); +    Replaceall(out, "%", "_xx_mod"); +    Replaceall(out, "^", "_xx_xor"); +    Replaceall(out, "*", "_xx_star"); +    Replaceall(out, "&", "_xx_amp"); +    Replaceall(out, "|", "_xx_or"); +    Replaceall(out, "(", "_xx_lparen"); +    Replaceall(out, ")", "_xx_rparen"); +    Replaceall(out, "[", "_xx_lbrace"); +    Replaceall(out, "]", "_xx_rbrace"); +    Replaceall(out, "~", "_xx_bnot"); +    Replaceall(out, "=", "_xx_equals"); +    Replaceall(out, "/", "_xx_slash"); +    Replaceall(out, ".", "_xx_dot"); +    return out; +  } + +  SwigType *fully_qualified_enum_type(Node *n) { +    Node *parent = 0; +    String *fully_qualified_name = NewString(""); +    String *parent_type = 0; + +    parent = parentNode(n); +    while (parent) { +      parent_type = nodeType(parent); +      if (Getattr(parent, "name")) { +	String *parent_copy = NewStringf("%s::", Getattr(parent, "name")); +	if (Cmp(parent_type, "class") == 0 || Cmp(parent_type, "namespace") == 0) +	  Insert(fully_qualified_name, 0, parent_copy); +	Delete(parent_copy); +      } +      if (!Cmp(parent_type, "class")) +	break; +      parent = parentNode(parent); +    } + +    return fully_qualified_name; +  } + +  /* Benedikt Grundmann inspired --> Enum wrap styles */ + +  int enumvalueDeclaration(Node *n) { +    String *name = Getattr(n, "name"); +    String *symname = Getattr(n, "sym:name"); +    SwigType *qtype = 0; + +    if (name_qualifier_type) { +      qtype = Copy(name_qualifier_type); +      Printv(qtype, name, NIL); +    } + +    if (const_enum && qtype && symname && !Getattr(seen_enumvalues, symname)) { +      Setattr(seen_enumvalues, symname, "true"); +      SetFlag(n, "feature:immutable"); +      Setattr(n, "feature:enumvalue", "1");	// this does not appear to be used + +      Setattr(n, "qualified:name", SwigType_namestr(qtype)); + +      String *evname = SwigType_manglestr(qtype); +      Insert(evname, 0, "SWIG_ENUM_"); + +      Setattr(n, "feature:enumvname", symname); +      Setattr(n, "feature:symname", evname); +      Delete(evname); +      Printf(f_enumtypes_value, "| `%s\n", symname); + +      return Language::enumvalueDeclaration(n); +    } else +      return SWIG_OK; +  } + +  /* ------------------------------------------------------------------- +   * This function is a bit uglier than it deserves. +   * +   * I used to direct lookup the name of the enum.  Now that certain fixes +   * have been made in other places, the names of enums are now fully +   * qualified, which is a good thing, overall, but requires me to do +   * some legwork. +   * +   * The other thing that uglifies this function is the varying way that +   * typedef enum and enum are handled.  I need to produce consistent names, +   * which means looking up and registering by typedef and enum name. */ +  int enumDeclaration(Node *n) { +    if (getCurrentClass() && (cplus_mode != PUBLIC)) +      return SWIG_NOWRAP; + +    String *name = Getattr(n, "name"); +    if (name) { +      String *oname = NewString(name); +      /* name is now fully qualified */ +      String *fully_qualified_name = NewString(name); +      bool seen_enum = false; +      if (name_qualifier_type) +        Delete(name_qualifier_type); +      char *strip_position; +      name_qualifier_type = fully_qualified_enum_type(n); + +      strip_position = strstr(Char(oname), "::"); + +      while (strip_position) { +        strip_position += 2; +        oname = NewString(strip_position); +        strip_position = strstr(Char(oname), "::"); +      } + +      seen_enum = (Getattr(seen_enums, fully_qualified_name) ? true : false); + +      if (!seen_enum) { +        const_enum = true; +        Printf(f_enum_to_int, "| `%s -> (match y with\n", oname); +        Printf(f_int_to_enum, "| `%s -> C_enum (\n", oname); +        /* * * * A note about enum name resolution * * * * +         * This code should now work, but I think we can do a bit better. +         * The problem I'm having is that swig isn't very precise about +         * typedef name resolution.  My opinion is that SwigType_typedef +         * resolve_all should *always* return the enum tag if one exists, +         * rather than the admittedly friendlier enclosing typedef. +         *  +         * This would make one of the cases below unnecessary.  +         * * * */ +        Printf(f_mlbody, "let _ = Callback.register \"%s_marker\" (`%s)\n", fully_qualified_name, oname); +        if (!strncmp(Char(fully_qualified_name), "enum ", 5)) { +          String *fq_noenum = NewString(Char(fully_qualified_name) + 5); +          Printf(f_mlbody, +                 "let _ = Callback.register \"%s_marker\" (`%s)\n" "let _ = Callback.register \"%s_marker\" (`%s)\n", fq_noenum, oname, fq_noenum, name); +        } + +        Printf(f_enumtypes_type, "| `%s\n", oname); +        Insert(fully_qualified_name, 0, "enum "); +        Setattr(seen_enums, fully_qualified_name, n); +      } +    } + +    int ret = Language::enumDeclaration(n); + +    if (const_enum) { +      Printf(f_int_to_enum, "`Int y)\n"); +      Printf(f_enum_to_int, "| `Int x -> Swig.C_int x\n" "| _ -> raise (LabelNotFromThisEnum v))\n"); +    } + +    const_enum = false; + +    return ret; +  } + +  /* ---------------------------------------------------------------------------- +   * BEGIN C++ Director Class modifications +   * ------------------------------------------------------------------------- */ + +  /* +   * Modified polymorphism code for Ocaml language module. +   * +   * TODO +   * +   * Move some boilerplate code generation to Swig_...() functions. +   * +   */ + +  /* --------------------------------------------------------------- +   * classDirectorMethod() +   * +   * Emit a virtual director method to pass a method call on to the  +   * underlying Python object. +   * +   * --------------------------------------------------------------- */ + +  int classDirectorMethod(Node *n, Node *parent, String *super) { +    int is_void = 0; +    int is_pointer = 0; +    String *storage = Getattr(n, "storage"); +    String *value = Getattr(n, "value"); +    String *decl = Getattr(n, "decl"); +    String *returntype = Getattr(n, "type"); +    String *name = Getattr(n, "name"); +    String *classname = Getattr(parent, "sym:name"); +    String *c_classname = Getattr(parent, "name"); +    String *symname = Getattr(n, "sym:name"); +    String *declaration = NewString(""); +    ParmList *l = Getattr(n, "parms"); +    Wrapper *w = NewWrapper(); +    String *tm; +    String *wrap_args = NewString(""); +    int status = SWIG_OK; +    int idx; +    bool pure_virtual = false; +    bool ignored_method = GetFlag(n, "feature:ignore") ? true : false; + +    if (Cmp(storage, "virtual") == 0) { +      if (Cmp(value, "0") == 0) { +	pure_virtual = true; +      } +    } +    Printf(w->locals, "CAMLparam0();\n"); + +    /* determine if the method returns a pointer */ +    is_pointer = SwigType_ispointer_return(decl); +    is_void = (!Cmp(returntype, "void") && !is_pointer); + +    /* virtual method definition */ +    String *target; +    String *pclassname = NewStringf("SwigDirector_%s", classname); +    String *qualified_name = NewStringf("%s::%s", pclassname, name); +    SwigType *rtype = Getattr(n, "conversion_operator") ? 0 : Getattr(n, "classDirectorMethods:type"); +    target = Swig_method_decl(rtype, decl, qualified_name, l, 0); +    Printf(w->def, "%s", target); +    Delete(qualified_name); +    Delete(target); +    /* header declaration */ +    target = Swig_method_decl(rtype, decl, name, l, 1); +    Printf(declaration, "    virtual %s", target); +    Delete(target); + +    // Get any exception classes in the throws typemap +    if (Getattr(n, "noexcept")) { +      Append(w->def, " noexcept"); +      Append(declaration, " noexcept"); +    } +    ParmList *throw_parm_list = 0; +    if ((throw_parm_list = Getattr(n, "throws")) || Getattr(n, "throw")) { +      Parm *p; +      int gencomma = 0; + +      Append(w->def, " throw("); +      Append(declaration, " throw("); + +      if (throw_parm_list) +	Swig_typemap_attach_parms("throws", throw_parm_list, 0); +      for (p = throw_parm_list; p; p = nextSibling(p)) { +	if (Getattr(p, "tmap:throws")) { +	  if (gencomma++) { +	    Append(w->def, ", "); +	    Append(declaration, ", "); +	  } +	  String *str = SwigType_str(Getattr(p, "type"), 0); +	  Append(w->def, str); +	  Append(declaration, str); +	  Delete(str); +	} +      } +      Append(w->def, ")"); +      Append(declaration, ")"); +    } +    Append(w->def, " {"); +    Append(declaration, ";\n"); +    /* declare method return value  +     * if the return value is a reference or const reference, a specialized typemap must +     * handle it, including declaration of c_result ($result). +     */ +    if (!is_void && (!ignored_method || pure_virtual)) { +      if (!SwigType_isclass(returntype)) { +	if (!(SwigType_ispointer(returntype) || SwigType_isreference(returntype))) { +	  String *construct_result = NewStringf("= SwigValueInit< %s >()", SwigType_lstr(returntype, 0)); +	  Wrapper_add_localv(w, "c_result", SwigType_lstr(returntype, "c_result"), construct_result, NIL); +	  Delete(construct_result); +	} else { +	  Wrapper_add_localv(w, "c_result", SwigType_lstr(returntype, "c_result"), "= 0", NIL); +	} +      } else { +	String *cres = SwigType_lstr(returntype, "c_result"); +	Printf(w->code, "%s;\n", cres); +	Delete(cres); +      } +    } + +    if (ignored_method) { +      if (!pure_virtual) { +	String *super_call = Swig_method_call(super, l); +	if (is_void) +	  Printf(w->code, "%s;\n", super_call); +	else +	  Printf(w->code, "CAMLreturn_type(%s);\n", super_call); +	Delete(super_call); +      } else { +	Printf(w->code, "Swig::DirectorPureVirtualException::raise(\"Attempted to invoke pure virtual method %s::%s\");\n", SwigType_namestr(c_classname), +	       SwigType_namestr(name)); +      } +    } else { +      Wrapper_add_local(w, "swig_result", "SWIG_CAMLlocal2(swig_result, args)"); +      /* attach typemaps to arguments (C/C++ -> Ocaml) */ +      String *arglist = NewString(""); + +      Swig_director_parms_fixup(l); + +      Swig_typemap_attach_parms("in", l, 0); +      Swig_typemap_attach_parms("directorin", l, w); +      Swig_typemap_attach_parms("directorargout", l, w); + +      Parm *p; +      int num_arguments = emit_num_arguments(l); +      int i; +      char source[256]; + +      /* build argument list and type conversion string */ +      for (i = 0, idx = 0, p = l; i < num_arguments; i++) { + +	while (Getattr(p, "tmap:ignore")) { +	  p = Getattr(p, "tmap:ignore:next"); +	} + +	String *pname = Getattr(p, "name"); +	String *ptype = Getattr(p, "type"); + +	Putc(',', arglist); +	if ((tm = Getattr(p, "tmap:directorin")) != 0) { +	  Setattr(p, "emit:directorinput", pname); +	  Replaceall(tm, "$input", pname); +	  Replaceall(tm, "$owner", "0"); +	  if (Len(tm) == 0) +	    Append(tm, pname); +	  Printv(wrap_args, tm, "\n", NIL); +	  p = Getattr(p, "tmap:directorin:next"); +	  continue; +	} else if (Cmp(ptype, "void")) { +	  /* special handling for pointers to other C++ director classes. +	   * ideally this would be left to a typemap, but there is currently no +	   * way to selectively apply the dynamic_cast<> to classes that have +	   * directors.  in other words, the type "SwigDirector_$1_lname" only exists +	   * for classes with directors.  we avoid the problem here by checking +	   * module.wrap::directormap, but it's not clear how to get a typemap to +	   * do something similar.  perhaps a new default typemap (in addition +	   * to SWIGTYPE) called DIRECTORTYPE? +	   */ +	  if (SwigType_ispointer(ptype) || SwigType_isreference(ptype)) { +	    Node *module = Getattr(parent, "module"); +	    Node *target = Swig_directormap(module, ptype); +	    sprintf(source, "obj%d", idx++); +	    String *nonconst = 0; +	    /* strip pointer/reference --- should move to Swig/stype.c */ +	    String *nptype = NewString(Char(ptype) + 2); +	    /* name as pointer */ +	    String *ppname = Copy(pname); +	    if (SwigType_isreference(ptype)) { +	      Insert(ppname, 0, "&"); +	    } +	    /* if necessary, cast away const since Python doesn't support it! */ +	    if (SwigType_isconst(nptype)) { +	      nonconst = NewStringf("nc_tmp_%s", pname); +	      String *nonconst_i = NewStringf("= const_cast< %s >(%s)", SwigType_lstr(ptype, 0), ppname); +	      Wrapper_add_localv(w, nonconst, SwigType_lstr(ptype, 0), nonconst, nonconst_i, NIL); +	      Delete(nonconst_i); +	      Swig_warning(WARN_LANG_DISCARD_CONST, input_file, line_number, +			   "Target language argument '%s' discards const in director method %s::%s.\n", SwigType_str(ptype, pname), +			   SwigType_namestr(c_classname), SwigType_namestr(name)); +	    } else { +	      nonconst = Copy(ppname); +	    } +	    Delete(nptype); +	    Delete(ppname); +	    String *mangle = SwigType_manglestr(ptype); +	    if (target) { +	      String *director = NewStringf("director_%s", mangle); +	      Wrapper_add_localv(w, director, "Swig::Director *", director, "= 0", NIL); +	      Wrapper_add_localv(w, source, "CAML_VALUE", source, "= Val_unit", NIL); +	      Printf(wrap_args, "%s = dynamic_cast<Swig::Director *>(%s);\n", director, nonconst); +	      Printf(wrap_args, "if (!%s) {\n", director); +	      Printf(wrap_args, "%s = SWIG_NewPointerObj(%s, SWIGTYPE%s, 0);\n", source, nonconst, mangle); +	      Printf(wrap_args, "} else {\n"); +	      Printf(wrap_args, "%s = %s->swig_get_self();\n", source, director); +	      Printf(wrap_args, "}\n"); +	      Delete(director); +	      Printv(arglist, source, NIL); +	    } else { +	      Wrapper_add_localv(w, source, "CAML_VALUE", source, "= Val_unit", NIL); +	      Printf(wrap_args, "%s = SWIG_NewPointerObj(%s, SWIGTYPE%s, 0);\n", source, nonconst, mangle); +	      //Printf(wrap_args, "%s = SWIG_NewPointerObj(%s, SWIGTYPE_p_%s, 0);\n",  +	      //       source, nonconst, base); +	      Printv(arglist, source, NIL); +	    } +	    Delete(mangle); +	    Delete(nonconst); +	  } else { +	    Swig_warning(WARN_TYPEMAP_DIRECTORIN_UNDEF, input_file, line_number, +			 "Unable to use type %s as a function argument in director method %s::%s (skipping method).\n", SwigType_str(ptype, 0), +			 SwigType_namestr(c_classname), SwigType_namestr(name)); +	    status = SWIG_NOWRAP; +	    break; +	  } +	} +	p = nextSibling(p); +      } + +      Printv(w->code, "swig_result = Val_unit;\n", 0); +      Printf(w->code, "args = Val_unit;\n"); + +      /* wrap complex arguments to values */ +      Printv(w->code, wrap_args, NIL); + +      /* pass the method call on to the OCaml object */ +      Printv(w->code, +	     "swig_result = caml_swig_alloc(1,C_list);\n" "SWIG_Store_field(swig_result,0,args);\n" "args = swig_result;\n" "swig_result = Val_unit;\n", 0); +      Printf(w->code, "static const CAML_VALUE *swig_ocaml_func_val = NULL;\n" "if (!swig_ocaml_func_val) {\n"); +      Printf(w->code, "  swig_ocaml_func_val = caml_named_value(\"swig_runmethod\");\n  }\n"); +      Printf(w->code, "swig_result = caml_callback3(*swig_ocaml_func_val,swig_get_self(),caml_copy_string(\"%s\"),args);\n", Getattr(n, "name")); +      /* exception handling */ +      tm = Swig_typemap_lookup("director:except", n, Swig_cresult_name(), 0); +      if (!tm) { +	tm = Getattr(n, "feature:director:except"); +      } +      if ((tm) && Len(tm) && (Strcmp(tm, "1") != 0)) { +	Printf(w->code, "if (!%s) {\n", Swig_cresult_name()); +	Printf(w->code, "  CAML_VALUE error = *caml_named_value(\"director_except\");\n"); +	Replaceall(tm, "$error", "error"); +	Printv(w->code, Str(tm), "\n", NIL); +	Printf(w->code, "}\n"); +      } + +      /* +       * Python method may return a simple object, or a tuple. +       * for in/out arguments, we have to extract the appropriate values from the +       * argument list, then marshal everything back to C/C++ (return value and +       * output arguments). +       */ + +      /* marshal return value and other outputs (if any) from value to C/C++  +       * type */ + +      String *cleanup = NewString(""); +      String *outarg = NewString(""); + +      tm = Swig_typemap_lookup("directorout", n, "c_result", w); +      if (tm != 0) { +	Replaceall(tm, "$input", "swig_result"); +	/* TODO check this */ +	if (Getattr(n, "wrap:disown")) { +	  Replaceall(tm, "$disown", "SWIG_POINTER_DISOWN"); +	} else { +	  Replaceall(tm, "$disown", "0"); +	} +	Replaceall(tm, "$result", "c_result"); +	Printv(w->code, tm, "\n", NIL); +      } + +      /* marshal outputs */ +      for (p = l; p;) { +	if ((tm = Getattr(p, "tmap:directorargout")) != 0) { +	  Replaceall(tm, "$result", "swig_result"); +	  Replaceall(tm, "$input", Getattr(p, "emit:directorinput")); +	  Printv(w->code, tm, "\n", NIL); +	  p = Getattr(p, "tmap:directorargout:next"); +	} else { +	  p = nextSibling(p); +	} +      } + +      Delete(arglist); +      Delete(cleanup); +      Delete(outarg); +    } + +    /* any existing helper functions to handle this? */ +    if (!is_void) { +      if (!(ignored_method && !pure_virtual)) { +	String *rettype = SwigType_str(returntype, 0); +	if (!SwigType_isreference(returntype)) { +	  Printf(w->code, "CAMLreturn_type((%s)c_result);\n", rettype); +	} else { +	  Printf(w->code, "CAMLreturn_type((%s)*c_result);\n", rettype); +	} +	Delete(rettype); +      } +    } else { +      Printf(w->code, "CAMLreturn0;\n"); +    } + +    Printf(w->code, "}\n"); + +    // We expose protected methods via an extra public inline method which makes a straight call to the wrapped class' method +    String *inline_extra_method = NewString(""); +    if (dirprot_mode() && !is_public(n) && !pure_virtual) { +      Printv(inline_extra_method, declaration, NIL); +      String *extra_method_name = NewStringf("%sSwigPublic", name); +      Replaceall(inline_extra_method, name, extra_method_name); +      Replaceall(inline_extra_method, ";\n", " {\n      "); +      if (!is_void) +	Printf(inline_extra_method, "return "); +      String *methodcall = Swig_method_call(super, l); +      Printv(inline_extra_method, methodcall, ";\n    }\n", NIL); +      Delete(methodcall); +      Delete(extra_method_name); +    } + +    /* emit the director method */ +    if (status == SWIG_OK) { +      if (!Getattr(n, "defaultargs")) { +	Replaceall(w->code, "$symname", symname); +	Wrapper_print(w, f_directors); +	Printv(f_directors_h, declaration, NIL); +	Printv(f_directors_h, inline_extra_method, NIL); +      } +    } + +    /* clean up */ +    Delete(wrap_args); +    Delete(pclassname); +    DelWrapper(w); +    return status; +  } + +  /* ------------------------------------------------------------ +   * classDirectorConstructor() +   * ------------------------------------------------------------ */ + +  int classDirectorConstructor(Node *n) { +    Node *parent = Getattr(n, "parentNode"); +    String *sub = NewString(""); +    String *decl = Getattr(n, "decl"); +    String *supername = Swig_class_name(parent); +    String *classname = NewString(""); +    Printf(classname, "SwigDirector_%s", supername); + +    /* insert self parameter */ +    Parm *p, *q; +    ParmList *superparms = Getattr(n, "parms"); +    ParmList *parms = CopyParmList(superparms); +    String *type = NewString("CAML_VALUE"); +    p = NewParm(type, NewString("self"), n); +    q = Copy(p); +    set_nextSibling(q, superparms); +    set_nextSibling(p, parms); +    parms = p; + +    if (!Getattr(n, "defaultargs")) { +      /* constructor */ +      { +	Wrapper *w = NewWrapper(); +	String *call; +	String *basetype = Getattr(parent, "classtype"); +	String *target = Swig_method_decl(0, decl, classname, parms, 0); +	call = Swig_csuperclass_call(0, basetype, superparms); +	Printf(w->def, "%s::%s: %s, Swig::Director(self) { }", classname, target, call); +	Delete(target); +	Wrapper_print(w, f_directors); +	Delete(call); +	DelWrapper(w); +      } + +      /* constructor header */ +      { +	String *target = Swig_method_decl(0, decl, classname, parms, 1); +	Printf(f_directors_h, "    %s;\n", target); +	Delete(target); +      } +    } + +    Setattr(n, "parms", q); +    Language::classDirectorConstructor(n); + +    Delete(sub); +    Delete(classname); +    Delete(supername); +    //Delete(parms);         + +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * classDirectorDefaultConstructor() +   * ------------------------------------------------------------ */ + +  int classDirectorDefaultConstructor(Node *n) { +    String *classname; +    classname = Swig_class_name(n); + +    /* insert self parameter */ +    Parm *p, *q; +    ParmList *superparms = Getattr(n, "parms"); +    ParmList *parms = CopyParmList(superparms); +    String *type = NewString("CAML_VALUE"); +    p = NewParm(type, NewString("self"), n); +    q = Copy(p); +    set_nextSibling(p, parms); + +    { +      Wrapper *w = NewWrapper(); +      Printf(w->def, "SwigDirector_%s::SwigDirector_%s(CAML_VALUE self) : Swig::Director(self) { }", classname, classname); +      Wrapper_print(w, f_directors); +      DelWrapper(w); +    } +    Printf(f_directors_h, "    SwigDirector_%s(CAML_VALUE self);\n", classname); +    Delete(classname); +    Setattr(n, "parms", q); +    return Language::classDirectorDefaultConstructor(n); +  } + +  int classDirectorInit(Node *n) { +    String *declaration = Swig_director_declaration(n); +    Printf(f_directors_h, "\n" "%s\n" "public:\n", declaration); +    Delete(declaration); +    return Language::classDirectorInit(n); +  } + +  int classDirectorEnd(Node *n) { +    Printf(f_directors_h, "};\n\n"); +    return Language::classDirectorEnd(n); +  } + +  /* --------------------------------------------------------------------- +   * typedefHandler +   * +   * This is here in order to maintain the correct association between +   * typedef names and enum names.  +   * +   * Since I implement enums as polymorphic variant tags, I need to call +   * back into ocaml to evaluate them.  This requires a string that can +   * be generated in the typemaps, and also at SWIG time to be the same +   * string.  The problem that arises is that SWIG variously generates +   * enum e_name_tag +   * e_name_tag +   * e_typedef_name +   * for +   * typedef enum e_name_tag { ... } e_typedef_name; +   *  +   * Since I need these strings to be consistent, I must maintain a correct +   * association list between typedef and enum names. +   * --------------------------------------------------------------------- */ +  int typedefHandler(Node *n) { +    String *type = Getattr(n, "type"); +    Node *enum_node = type ? Getattr(seen_enums, type) : 0; +    if (enum_node) { +      String *name = Getattr(enum_node, "name"); + +      Printf(f_mlbody, "let _ = Callback.register \"%s_marker\" (`%s)\n", Getattr(n, "name"), name); + +    } +    return SWIG_OK; +  } + +  String *runtimeCode() { +    String *s = Swig_include_sys("ocamlrun.swg"); +    if (!s) { +      Printf(stderr, "*** Unable to open 'ocamlrun.swg'\n"); +      s = NewString(""); +    } +    return s; +  } + +  String *defaultExternalRuntimeFilename() { +    return NewString("swigocamlrun.h"); +  } +}; + +/* ------------------------------------------------------------------------- + * swig_ocaml()    - Instantiate module + * ------------------------------------------------------------------------- */ + +static Language *new_swig_ocaml() { +  return new OCAML(); +} +extern "C" Language *swig_ocaml(void) { +  return new_swig_ocaml(); +} diff --git a/contrib/tools/swig/Source/Modules/octave.cxx b/contrib/tools/swig/Source/Modules/octave.cxx new file mode 100644 index 00000000000..352105b9bda --- /dev/null +++ b/contrib/tools/swig/Source/Modules/octave.cxx @@ -0,0 +1,1572 @@ +/* ----------------------------------------------------------------------------- + * This file is part of SWIG, which is licensed as a whole under version 3 + * (or any later version) of the GNU General Public License. Some additional + * terms also apply to certain portions of SWIG. The full details of the SWIG + * license and copyrights can be found in the LICENSE and COPYRIGHT files + * included with the SWIG source code as distributed by the SWIG developers + * and at https://www.swig.org/legal.html. + * + * octave.cxx + * + * Octave language module for SWIG. + * ----------------------------------------------------------------------------- */ + +#include "swigmod.h" +#include "cparse.h" + +static String *global_name = 0; +static String *op_prefix   = 0; + +static const char *usage = "\ +Octave Options (available with -octave)\n\ +     -globals <name> - Set <name> used to access C global variables [default: 'cvar']\n\ +                       Use '.' to load C global variables into module namespace\n\ +     -opprefix <str> - Prefix <str> for global operator functions [default: 'op_']\n\ +\n"; + + +class OCTAVE:public Language { +private: +  File *f_begin; +  File *f_runtime; +  File *f_header; +  File *f_doc; +  File *f_wrappers; +  File *f_init; +  File *f_initbeforefunc; +  File *f_directors; +  File *f_directors_h; +  String *s_global_tab; +  String *s_members_tab; +  String *class_name; + +  int have_constructor; +  int have_destructor; +  String *constructor_name; + +  Hash *docs; + +  void Octave_begin_function(Node *n, File *f, const_String_or_char_ptr cname, const_String_or_char_ptr wname, bool dld) { +    if (dld) { +      String *tname = texinfo_name(n, "std::string()"); +      Printf(f, "SWIG_DEFUN( %s, %s, %s ) {", cname, wname, tname); +    } +    else { +      Printf(f, "static octave_value_list %s (const octave_value_list& args, int nargout) {", wname); +    } +  } + +public: +  OCTAVE(): +    f_begin(0), +    f_runtime(0), +    f_header(0), +    f_doc(0), +    f_wrappers(0), +    f_init(0), +    f_initbeforefunc(0), +    f_directors(0), +    f_directors_h(0), +    s_global_tab(0), +    s_members_tab(0), +    class_name(0), +    have_constructor(0), +    have_destructor(0), +    constructor_name(0), +    docs(0) +  { +    /* Add code to manage protected constructors and directors */ +    director_prot_ctor_code = NewString(""); +    Printv(director_prot_ctor_code, +           "if ( $comparison ) { /* subclassed */\n", +           "  $director_new \n", +           "} else {\n", "  error(\"accessing abstract class or protected constructor\"); \n", "  SWIG_fail;\n", "}\n", NIL); + +    enable_cplus_runtime_mode(); +    allow_overloading(); +    director_multiple_inheritance = 1; +    director_language = 1; +    docs = NewHash(); +  } + +  virtual void main(int argc, char *argv[]) { + +    for (int i = 1; i < argc; i++) { +      if (argv[i]) { +        if (strcmp(argv[i], "-help") == 0) { +          fputs(usage, stdout); +        } else if (strcmp(argv[i], "-globals") == 0) { +          if (argv[i + 1]) { +            global_name = NewString(argv[i + 1]); +            Swig_mark_arg(i); +            Swig_mark_arg(i + 1); +            i++; +          } else { +            Swig_arg_error(); +          } +        } else if (strcmp(argv[i], "-opprefix") == 0) { +          if (argv[i + 1]) { +            op_prefix = NewString(argv[i + 1]); +            Swig_mark_arg(i); +            Swig_mark_arg(i + 1); +            i++; +          } else { +            Swig_arg_error(); +          } +	} else if (strcmp(argv[i], "-cppcast") == 0) { +	  Printf(stderr, "Deprecated command line option: %s. This option is now always on.\n", argv[i]); +	  Swig_mark_arg(i); +	} else if (strcmp(argv[i], "-nocppcast") == 0) { +	  Printf(stderr, "Deprecated command line option: %s. This option is no longer supported.\n", argv[i]); +	  Swig_mark_arg(i); +	  Exit(EXIT_FAILURE); +        } +      } +    } + +    if (!global_name) +      global_name = NewString("cvar"); +    if (!op_prefix) +      op_prefix = NewString("op_"); + +    SWIG_library_directory("octave"); +    Preprocessor_define("SWIGOCTAVE 1", 0); +    SWIG_config_file("octave.swg"); +    SWIG_typemap_lang("octave"); +    allow_overloading(); + +    // Octave API is C++, so output must be C++ compatible even when wrapping C code +    if (!cparse_cplusplus) +      Swig_cparse_cplusplusout(1); +  } + +  virtual int top(Node *n) { +    { +      Node *mod = Getattr(n, "module"); +      if (mod) { +        Node *options = Getattr(mod, "options"); +        if (options) { +          int dirprot = 0; +          if (Getattr(options, "dirprot")) { +            dirprot = 1; +          } +          if (Getattr(options, "nodirprot")) { +            dirprot = 0; +          } +          if (Getattr(options, "directors")) { +            allow_directors(); +            if (dirprot) +              allow_dirprot(); +          } +        } +      } +    } + +    String *module = Getattr(n, "name"); +    String *outfile = Getattr(n, "outfile"); +    f_begin = NewFile(outfile, "w", SWIG_output_files()); +    if (!f_begin) { +      FileErrorDisplay(outfile); +      Exit(EXIT_FAILURE); +    } +    f_runtime = NewString(""); +    f_header = NewString(""); +    f_doc = NewString(""); +    f_wrappers = NewString(""); +    f_init = NewString(""); +    f_initbeforefunc = NewString(""); +    f_directors_h = NewString(""); +    f_directors = NewString(""); +    s_global_tab = NewString(""); +    Swig_register_filebyname("begin", f_begin); +    Swig_register_filebyname("runtime", f_runtime); +    Swig_register_filebyname("header", f_header); +    Swig_register_filebyname("doc", f_doc); +    Swig_register_filebyname("wrapper", f_wrappers); +    Swig_register_filebyname("init", f_init); +    Swig_register_filebyname("initbeforefunc", f_initbeforefunc); +    Swig_register_filebyname("director", f_directors); +    Swig_register_filebyname("director_h", f_directors_h); + +    Swig_banner(f_begin); + +    Swig_obligatory_macros(f_runtime, "OCTAVE"); + +    Printf(f_runtime, "#define SWIG_name_d      \"%s\"\n", module); +    Printf(f_runtime, "#define SWIG_name        %s\n", module); + +    Printf(f_runtime, "\n"); +    Printf(f_runtime, "#define SWIG_global_name      \"%s\"\n", global_name); +    Printf(f_runtime, "#define SWIG_op_prefix        \"%s\"\n", op_prefix); + +    if (directorsEnabled()) { +      Printf(f_runtime, "#define SWIG_DIRECTORS\n"); +      Swig_banner(f_directors_h); +      if (dirprot_mode()) { +        //      Printf(f_directors_h, "#include <map>\n"); +        //      Printf(f_directors_h, "#include <string>\n\n"); +      } +    } + +    Printf(f_runtime, "\n"); + +    Printf(s_global_tab, "\nstatic const struct swig_octave_member swig_globals[] = {\n"); +    Printf(f_init, "static bool SWIG_init_user(octave_swig_type* module_ns)\n{\n"); + +    if (!CPlusPlus) +      Printf(f_header,"extern \"C\" {\n"); + +    Language::top(n); + +    if (!CPlusPlus) +      Printf(f_header,"}\n"); + +    if (Len(docs)) +      emit_doc_texinfo(); + +    if (directorsEnabled()) { +      Swig_insert_file("director_common.swg", f_runtime); +      Swig_insert_file("director.swg", f_runtime); +    } + +    Printf(f_init, "return true;\n}\n"); +    Printf(s_global_tab, "{0,0,0,0,0,0}\n};\n"); + +    Printv(f_wrappers, s_global_tab, NIL); +    SwigType_emit_type_table(f_runtime, f_wrappers); +    Dump(f_runtime, f_begin); +    Dump(f_header, f_begin); +    Dump(f_doc, f_begin); +    if (directorsEnabled()) { +      Dump(f_directors_h, f_begin); +      Dump(f_directors, f_begin); +    } +    Dump(f_wrappers, f_begin); +    Dump(f_initbeforefunc, f_begin); +    Wrapper_pretty_print(f_init, f_begin); + +    Delete(s_global_tab); +    Delete(f_initbeforefunc); +    Delete(f_init); +    Delete(f_wrappers); +    Delete(f_doc); +    Delete(f_header); +    Delete(f_directors); +    Delete(f_directors_h); +    Delete(f_runtime); +    Delete(f_begin); + +    return SWIG_OK; +  } + +  String *texinfo_escape(String *_s) { +    const char* s=(const char*)Data(_s); +    while (*s&&(*s=='\t'||*s=='\r'||*s=='\n'||*s==' ')) +      ++s; +    String *r = NewString(""); +    for (int j=0;s[j];++j) { +      if (s[j] == '\n') { +        Append(r, "\\n\\\n"); +      } else if (s[j] == '\r') { +        Append(r, "\\r"); +      } else if (s[j] == '\t') { +        Append(r, "\\t"); +      } else if (s[j] == '\\') { +        Append(r, "\\\\"); +      } else if (s[j] == '\'') { +        Append(r, "\\\'"); +      } else if (s[j] == '\"') { +        Append(r, "\\\""); +      } else +        Putc(s[j], r); +    } +    return r; +  } +  void emit_doc_texinfo() { +    for (Iterator it = First(docs); it.key; it = Next(it)) { +      String *wrap_name = it.key; + +      String *synopsis = Getattr(it.item, "synopsis"); +      String *decl_info = Getattr(it.item, "decl_info"); +      String *cdecl_info = Getattr(it.item, "cdecl_info"); +      String *args_info = Getattr(it.item, "args_info"); + +      String *doc_str = NewString(""); +      Printv(doc_str, synopsis, decl_info, cdecl_info, args_info, NIL); +      String *escaped_doc_str = texinfo_escape(doc_str); + +      if (Len(doc_str)>0) { +        Printf(f_doc,"static const char* %s_texinfo = ",wrap_name); +        Printf(f_doc,"\"-*- texinfo -*-\\n\\\n%s", escaped_doc_str); +        if (Len(decl_info)) +          Printf(f_doc,"\\n\\\n@end deftypefn"); +        Printf(f_doc,"\";\n"); +      } + +      Delete(escaped_doc_str); +      Delete(doc_str); +      Delete(wrap_name); +    } +    Printf(f_doc,"\n"); +  } +  bool is_empty_doc_node(Node* n) { +    if (!n) +      return true; +    String *synopsis = Getattr(n, "synopsis"); +    String *decl_info = Getattr(n, "decl_info"); +    String *cdecl_info = Getattr(n, "cdecl_info"); +    String *args_info = Getattr(n, "args_info"); +    return !Len(synopsis) && !Len(decl_info) && +      !Len(cdecl_info) && !Len(args_info); +  } +  String *texinfo_name(Node* n, const char* defval = "0") { +    String *tname = NewString(""); +    String *iname = Getattr(n, "sym:name"); +    String *wname = Swig_name_wrapper(iname); +    Node* d = Getattr(docs, wname); + +    if (is_empty_doc_node(d)) +      Printf(tname, defval); +    else +      Printf(tname, "%s_texinfo", wname); + +    return tname; +  } +  void process_autodoc(Node *n) { +    String *iname = Getattr(n, "sym:name"); +    String *name = Getattr(n, "name"); +    String *wname = Swig_name_wrapper(iname); +    String *str = Getattr(n, "feature:docstring"); +    bool autodoc_enabled = !Cmp(Getattr(n, "feature:autodoc"), "1"); +    Node* d = Getattr(docs, wname); +    if (!d) { +      d = NewHash(); +      Setattr(d, "synopsis", NewString("")); +      Setattr(d, "decl_info", NewString("")); +      Setattr(d, "cdecl_info", NewString("")); +      Setattr(d, "args_info", NewString("")); +      Setattr(docs, wname, d); +    } + +    String *synopsis = Getattr(d, "synopsis"); +    String *decl_info = Getattr(d, "decl_info"); +    //    String *cdecl_info = Getattr(d, "cdecl_info"); +    String *args_info = Getattr(d, "args_info"); + +    // * couldn't we just emit the docs here? + +    if (autodoc_enabled) { +      String *decl_str = NewString(""); +      String *args_str = NewString(""); +      make_autodocParmList(n, decl_str, args_str); +      Append(decl_info, "@deftypefn {Loadable Function} "); + +      SwigType *type = Getattr(n, "type"); +      if (type && Strcmp(type, "void")) { +        Node *nn = classLookup(Getattr(n, "type")); +        String *type_str = nn ? Copy(Getattr(nn, "sym:name")) : SwigType_str(type, 0); +        Append(decl_info, "@var{retval} = "); +        Printf(args_str, "%s@var{retval} is of type %s. ", args_str, type_str); +        Delete(type_str); +      } + +      Append(decl_info, name); +      Append(decl_info, " ("); +      Append(decl_info, decl_str); +      Append(decl_info, ")\n"); +      Append(args_info, args_str); +      Delete(decl_str); +      Delete(args_str); +    } + +    if (str && Len(str) > 0) { +      // strip off {} if necessary +      char *t = Char(str); +      if (*t == '{') { +        Delitem(str, 0); +        Delitem(str, DOH_END); +      } + +      // emit into synopsis section +      Append(synopsis, str); +    } +  } + +  virtual int importDirective(Node *n) { +    String *modname = Getattr(n, "module"); +    if (modname) +      Printf(f_init, "if (!SWIG_Octave_LoadModule(\"%s\")) return false;\n", modname); +    return Language::importDirective(n); +  } + +  const char *get_implicitconv_flag(Node *n) { +    int conv = 0; +    if (n && GetFlag(n, "feature:implicitconv")) { +      conv = 1; +    } +    return conv ? "SWIG_POINTER_IMPLICIT_CONV" : "0"; +  } + +  /* ----------------------------------------------------------------------------- +   * addMissingParameterNames() +   *  For functions that have not had nameless parameters set in the Language class. +   * +   * Inputs: +   *   plist - entire parameter list +   *   arg_offset - argument number for first parameter +   * Side effects: +   *   The "lname" attribute in each parameter in plist will be contain a parameter name +   * ----------------------------------------------------------------------------- */ + +  void addMissingParameterNames(Node* n, ParmList *plist, int arg_offset) { +    Parm *p = plist; +    int i = arg_offset; +    while (p) { +      if (!Getattr(p, "lname")) { +	String *name = makeParameterName(n, p, i); +	Setattr(p, "lname", name); +	Delete(name); +      } +      i++; +      p = nextSibling(p); +    } +  } + +  void make_autodocParmList(Node *n, String *decl_str, String *args_str) { +    String *pdocs = 0; +    ParmList *plist = CopyParmList(Getattr(n, "parms")); +    Parm *p; +    Parm *pnext; +    int arg_num = is_wrapping_class() ? 1 : 0; + +    addMissingParameterNames(n, plist, arg_num); // for $1_name substitutions done in Swig_typemap_attach_parms + +    Swig_typemap_attach_parms("in", plist, 0); +    Swig_typemap_attach_parms("doc", plist, 0); + +    for (p = plist; p; p = pnext, arg_num++) { + +      String *tm = Getattr(p, "tmap:in"); +      if (tm) { +        pnext = Getattr(p, "tmap:in:next"); +        if (checkAttribute(p, "tmap:in:numinputs", "0")) { +          continue; +        } +      } else { +        pnext = nextSibling(p); +      } + +      String *name = 0; +      String *type = 0; +      String *value = 0; +      String *pdoc = Getattr(p, "tmap:doc"); +      if (pdoc) { +        name = Getattr(p, "tmap:doc:name"); +        type = Getattr(p, "tmap:doc:type"); +        value = Getattr(p, "tmap:doc:value"); +      } + +      String *made_name = 0; +      if (!name) { +	name = made_name = makeParameterName(n, p, arg_num); +      } + +      type = type ? type : Getattr(p, "type"); +      value = value ? value : Getattr(p, "value"); + +      if (SwigType_isvarargs(type)) +        break; + +      String *tex_name = NewString(""); +      if (name) +        Printf(tex_name, "@var{%s}", name); +      else +        Printf(tex_name, "@var{?}"); + +      if (Len(decl_str)) +        Append(decl_str, ", "); +      Append(decl_str, tex_name); + +      if (value) { +        String *new_value = convertValue(value, Getattr(p, "type")); +        if (new_value) { +          value = new_value; +        } else { +          Node *lookup = Swig_symbol_clookup(value, 0); +          if (lookup) +            value = Getattr(lookup, "sym:name"); +        } +        Printf(decl_str, " = %s", value); +      } + +      Node *nn = classLookup(Getattr(p, "type")); +      String *type_str = nn ? Copy(Getattr(nn, "sym:name")) : SwigType_str(type, 0); +      Printf(args_str, "%s is of type %s. ", tex_name, type_str); + +      Delete(type_str); +      Delete(tex_name); +      Delete(made_name); +    } +    if (pdocs) +      Setattr(n, "feature:pdocs", pdocs); +    Delete(plist); +  } + +  /* ------------------------------------------------------------ +   * convertValue() +   *    Check if string v can be an Octave value literal, +   *    (eg. number or string), or translate it to an Octave literal. +   * ------------------------------------------------------------ */ +  String *convertValue(String *v, SwigType *t) { +    if (v && Len(v) > 0) { +      char fc = (Char(v))[0]; +      if (('0' <= fc && fc <= '9') || '\'' == fc || '"' == fc) { +        /* number or string (or maybe NULL pointer) */ +        if (SwigType_ispointer(t) && Strcmp(v, "0") == 0) +          return NewString("None"); +        else +          return v; +      } +      if (Strcmp(v, "NULL") == 0 || Strcmp(v, "nullptr") == 0) +        return SwigType_ispointer(t) ? NewString("nil") : NewString("0"); +      if (Strcmp(v, "true") == 0 || Strcmp(v, "TRUE") == 0) +        return NewString("true"); +      if (Strcmp(v, "false") == 0 || Strcmp(v, "FALSE") == 0) +        return NewString("false"); +    } +    return 0; +  } + +  virtual int functionWrapper(Node *n) { +    Parm *p; +    String *tm; +    int j; + +    String *nodeType = Getattr(n, "nodeType"); +    int constructor = (!Cmp(nodeType, "constructor")); +    int destructor = (!Cmp(nodeType, "destructor")); +    String *storage = Getattr(n, "storage"); + +    bool overloaded = !!Getattr(n, "sym:overloaded"); +    bool last_overload = overloaded && !Getattr(n, "sym:nextSibling"); +    String *iname = Getattr(n, "sym:name"); +    String *wname = Swig_name_wrapper(iname); +    String *overname = Copy(wname); +    SwigType *d = Getattr(n, "type"); +    ParmList *l = Getattr(n, "parms"); + +    if (!overloaded && !addSymbol(iname, n)) +      return SWIG_ERROR; + +    if (overloaded) +      Append(overname, Getattr(n, "sym:overname")); + +    if (!overloaded || last_overload) +      process_autodoc(n); + +    Wrapper *f = NewWrapper(); +    Octave_begin_function(n, f->def, iname, overname, !overloaded); + +    // Start default try block to execute +    // cleanup code if exception is thrown +    Printf(f->code, "try {\n"); + +    emit_parameter_variables(l, f); +    emit_attach_parmmaps(l, f); +    Setattr(n, "wrap:parms", l); + +    int num_arguments = emit_num_arguments(l); +    int num_required = emit_num_required(l); +    int varargs = emit_isvarargs(l); +    char source[64]; + +    Printf(f->code, "if (!SWIG_check_num_args(\"%s\",args.length(),%i,%i,%i)) " +           "{\n SWIG_fail;\n }\n", iname, num_arguments, num_required, varargs); + +    if (constructor && num_arguments == 1 && num_required == 1) { +      if (Cmp(storage, "explicit") == 0) { +        Node *parent = Swig_methodclass(n); +        if (GetFlag(parent, "feature:implicitconv")) { +          String *desc = NewStringf("SWIGTYPE%s", SwigType_manglestr(Getattr(n, "type"))); +          Printf(f->code, "if (SWIG_CheckImplicit(%s)) SWIG_fail;\n", desc); +          Delete(desc); +        } +      } +    } + +    for (j = 0, p = l; j < num_arguments; ++j) { +      while (checkAttribute(p, "tmap:in:numinputs", "0")) { +        p = Getattr(p, "tmap:in:next"); +      } + +      SwigType *pt = Getattr(p, "type"); + +      String *tm = Getattr(p, "tmap:in"); +      if (tm) { +        if (!tm || checkAttribute(p, "tmap:in:numinputs", "0")) { +          p = nextSibling(p); +          continue; +        } + +        sprintf(source, "args(%d)", j); +        Setattr(p, "emit:input", source); + +        Replaceall(tm, "$input", Getattr(p, "emit:input")); + +        if (Getattr(p, "wrap:disown") || (Getattr(p, "tmap:in:disown"))) { +          Replaceall(tm, "$disown", "SWIG_POINTER_DISOWN"); +        } else { +          Replaceall(tm, "$disown", "0"); +        } + +        if (Getattr(p, "tmap:in:implicitconv")) { +          const char *convflag = "0"; +          if (!Getattr(p, "hidden")) { +            SwigType *ptype = Getattr(p, "type"); +            convflag = get_implicitconv_flag(classLookup(ptype)); +          } +          Replaceall(tm, "$implicitconv", convflag); +          Setattr(p, "implicitconv", convflag); +        } + +        String *getargs = NewString(""); +        if (j >= num_required) +          Printf(getargs, "if (%d<args.length()) {\n%s\n}", j, tm); +        else +          Printv(getargs, tm, NIL); +        Printv(f->code, getargs, "\n", NIL); +        Delete(getargs); + +        p = Getattr(p, "tmap:in:next"); +        continue; +      } else { +        Swig_warning(WARN_TYPEMAP_IN_UNDEF, input_file, line_number, "Unable to use type %s as a function argument.\n", SwigType_str(pt, 0)); +        break; +      } +    } + +    // Check for trailing varargs +    if (varargs) { +      if (p && (tm = Getattr(p, "tmap:in"))) { +        Replaceall(tm, "$input", "varargs"); +        Printv(f->code, tm, "\n", NIL); +      } +    } + +    // Insert constraint checking code +    for (p = l; p;) { +      if ((tm = Getattr(p, "tmap:check"))) { +        Printv(f->code, tm, "\n", NIL); +        p = Getattr(p, "tmap:check:next"); +      } else { +        p = nextSibling(p); +      } +    } + +    // Insert cleanup code +    String *cleanup = NewString(""); +    for (p = l; p;) { +      if ((tm = Getattr(p, "tmap:freearg"))) { +        if (Getattr(p, "tmap:freearg:implicitconv")) { +          const char *convflag = "0"; +          if (!Getattr(p, "hidden")) { +            SwigType *ptype = Getattr(p, "type"); +            convflag = get_implicitconv_flag(classLookup(ptype)); +          } +          if (strcmp(convflag, "0") == 0) { +            tm = 0; +          } +        } +        if (tm && (Len(tm) != 0)) { +          Printv(cleanup, tm, "\n", NIL); +        } +        p = Getattr(p, "tmap:freearg:next"); +      } else { +        p = nextSibling(p); +      } +    } + +    // Insert argument output code +    String *outarg = NewString(""); +    for (p = l; p;) { +      if ((tm = Getattr(p, "tmap:argout"))) { +        Replaceall(tm, "$result", "_outp"); +        Replaceall(tm, "$arg", Getattr(p, "emit:input")); +        Replaceall(tm, "$input", Getattr(p, "emit:input")); +        Printv(outarg, tm, "\n", NIL); +        p = Getattr(p, "tmap:argout:next"); +      } else { +        p = nextSibling(p); +      } +    } + +    int director_method = is_member_director(n) && !is_smart_pointer() && !destructor; +    if (director_method) { +      Wrapper_add_local(f, "upcall", "bool upcall = false"); +      Append(f->code, "upcall = !!dynamic_cast<Swig::Director*>(arg1);\n"); +    } + +    Setattr(n, "wrap:name", overname); + +    Swig_director_emit_dynamic_cast(n, f); +    String *actioncode = emit_action(n); + +    Wrapper_add_local(f, "_out", "octave_value_list _out"); +    Wrapper_add_local(f, "_outp", "octave_value_list *_outp=&_out"); +    Wrapper_add_local(f, "_outv", "octave_value _outv"); + +    // Return the function value +    if ((tm = Swig_typemap_lookup_out("out", n, Swig_cresult_name(), f, actioncode))) { +      Replaceall(tm, "$result", "_outv"); + +      if (GetFlag(n, "feature:new")) +        Replaceall(tm, "$owner", "1"); +      else +        Replaceall(tm, "$owner", "0"); + +      Printf(f->code, "%s\n", tm); +      Printf(f->code, "if (_outv.is_defined()) _outp = " "SWIG_Octave_AppendOutput(_outp, _outv);\n"); +      Delete(tm); +    } else { +      Swig_warning(WARN_TYPEMAP_OUT_UNDEF, input_file, line_number, "Unable to use return type %s in function %s.\n", SwigType_str(d, 0), iname); +    } +    emit_return_variable(n, d, f); + +    Printv(f->code, outarg, NIL); +    Printv(f->code, cleanup, NIL); + +    if (GetFlag(n, "feature:new")) { +      if ((tm = Swig_typemap_lookup("newfree", n, Swig_cresult_name(), 0))) { +        Printf(f->code, "%s\n", tm); +      } +    } + +    if ((tm = Swig_typemap_lookup("ret", n, Swig_cresult_name(), 0))) { +      Replaceall(tm, "$result", "_outv"); +      Printf(f->code, "%s\n", tm); +      Delete(tm); +    } + +    Printf(f->code, "return _out;\n"); + +    // Execute cleanup code if branched to fail: label +    Printf(f->code, "fail:\n"); +    Printv(f->code, cleanup, NIL); +    Printf(f->code, "return octave_value_list();\n"); + +    // Execute cleanup code if exception was thrown +    Printf(f->code, "}\n"); +    Printf(f->code, "catch(...) {\n"); +    Printv(f->code, cleanup, NIL); +    Printf(f->code, "throw;\n"); +    Printf(f->code, "}\n"); + +    // End wrapper function +    Printf(f->code, "}\n"); + +    /* Substitute the cleanup code */ +    Replaceall(f->code, "$cleanup", cleanup); + +    Replaceall(f->code, "$symname", iname); +    Wrapper_print(f, f_wrappers); +    DelWrapper(f); + +    if (last_overload) +      dispatchFunction(n); + +    if (!overloaded || last_overload) { +      String *tname = texinfo_name(n); +      Printf(s_global_tab, "{\"%s\",%s,0,0,2,%s},\n", iname, wname, tname); +      Delete(tname); +    } + +    Delete(overname); +    Delete(wname); +    Delete(cleanup); +    Delete(outarg); + +    return SWIG_OK; +  } + +  void dispatchFunction(Node *n) { +    Wrapper *f = NewWrapper(); + +    String *iname = Getattr(n, "sym:name"); +    String *wname = Swig_name_wrapper(iname); +    int maxargs; +    String *dispatch = Swig_overload_dispatch(n, "return %s(args, nargout);", &maxargs); +    String *tmp = NewString(""); + +    Octave_begin_function(n, f->def, iname, wname, true); +    Wrapper_add_local(f, "argc", "int argc = args.length()"); +    Printf(tmp, "octave_value_ref argv[%d]={", maxargs); +    for (int j = 0; j < maxargs; ++j) +      Printf(tmp, "%soctave_value_ref(args,%d)", j ? "," : " ", j); +    Printf(tmp, "}"); +    Wrapper_add_local(f, "argv", tmp); +    Printv(f->code, dispatch, "\n", NIL); +    Printf(f->code, "error(\"No matching function for overload\");\n"); +    Printf(f->code, "return octave_value_list();\n"); +    Printv(f->code, "}\n", NIL); + +    Wrapper_print(f, f_wrappers); +    Delete(tmp); +    DelWrapper(f); +    Delete(dispatch); +    Delete(wname); +  } + +  virtual int variableWrapper(Node *n) { +    String *name = Getattr(n, "name"); +    String *iname = Getattr(n, "sym:name"); +    SwigType *t = Getattr(n, "type"); + +    if (!addSymbol(iname, n)) +      return SWIG_ERROR; + +    String *tm; +    Wrapper *getf = NewWrapper(); +    Wrapper *setf = NewWrapper(); + +    String *getname = Swig_name_get(NSPACE_TODO, iname); +    String *setname = Swig_name_set(NSPACE_TODO, iname); + +    String *getwname = Swig_name_wrapper(getname); +    String *setwname = Swig_name_wrapper(setname); + +    Octave_begin_function(n, setf->def, setname, setwname, true); +    Printf(setf->code, "if (!SWIG_check_num_args(\"%s_set\",args.length(),1,1,0)) return octave_value_list();\n", iname); +    if (is_assignable(n)) { +      Setattr(n, "wrap:name", setname); +      if ((tm = Swig_typemap_lookup("varin", n, name, 0))) { +        Replaceall(tm, "$input", "args(0)"); +        if (Getattr(n, "tmap:varin:implicitconv")) { +          Replaceall(tm, "$implicitconv", get_implicitconv_flag(n)); +        } +        emit_action_code(n, setf->code, tm); +        Delete(tm); +      } else { +        Swig_warning(WARN_TYPEMAP_VARIN_UNDEF, input_file, line_number, "Unable to set variable of type %s.\n", SwigType_str(t, 0)); +      } +      Append(setf->code, "return octave_value_list();\n"); +      Append(setf->code, "fail:\n"); +      Append(setf->code, "return octave_value_list();\n"); +    } else { +      Printf(setf->code, "return octave_set_immutable(args,nargout);"); +    } +    Append(setf->code, "}\n"); +    Wrapper_print(setf, f_wrappers); + +    Setattr(n, "wrap:name", getname); +    int addfail = 0; +    Octave_begin_function(n, getf->def, getname, getwname, true); +    Wrapper_add_local(getf, "obj", "octave_value obj"); +    if ((tm = Swig_typemap_lookup("varout", n, name, 0))) { +      Replaceall(tm, "$result", "obj"); +      addfail = emit_action_code(n, getf->code, tm); +      Delete(tm); +    } else { +      Swig_warning(WARN_TYPEMAP_VAROUT_UNDEF, input_file, line_number, "Unable to read variable of type %s\n", SwigType_str(t, 0)); +    } +    Append(getf->code, "return obj;\n"); +    if (addfail) { +      Append(getf->code, "fail:\n"); +      Append(getf->code, "return octave_value_list();\n"); +    } +    Append(getf->code, "}\n"); +    Wrapper_print(getf, f_wrappers); + +    Printf(s_global_tab, "{\"%s\",0,%s,%s,2,0},\n", iname, getwname, setwname); + +    Delete(getwname); +    Delete(setwname); +    DelWrapper(setf); +    DelWrapper(getf); + +    return SWIG_OK; +  } + +  virtual int constantWrapper(Node *n) { +    String *name = Getattr(n, "name"); +    String *iname = Getattr(n, "sym:name"); +    SwigType *type = Getattr(n, "type"); +    String *rawval = Getattr(n, "rawval"); +    String *value = rawval ? rawval : Getattr(n, "value"); +    String *cppvalue = Getattr(n, "cppvalue"); +    String *tm; + +    if (!addSymbol(iname, n)) +      return SWIG_ERROR; + +    if (SwigType_type(type) == T_MPOINTER) { +      String *wname = Swig_name_wrapper(iname); +      String *str = SwigType_str(type, wname); +      Printf(f_header, "static %s = %s;\n", str, value); +      Delete(str); +      value = wname; +    } +    if ((tm = Swig_typemap_lookup("constcode", n, name, 0))) { +      Replaceall(tm, "$value", cppvalue ? cppvalue : value); +      Replaceall(tm, "$nsname", iname); +      Printf(f_init, "%s\n", tm); +    } else { +      Swig_warning(WARN_TYPEMAP_CONST_UNDEF, input_file, line_number, "Unsupported constant value.\n"); +      return SWIG_NOWRAP; +    } + +    return SWIG_OK; +  } + +  virtual int nativeWrapper(Node *n) { +    return Language::nativeWrapper(n); +  } + +  virtual int enumDeclaration(Node *n) { +    return Language::enumDeclaration(n); +  } + +  virtual int enumvalueDeclaration(Node *n) { +    return Language::enumvalueDeclaration(n); +  } + +  virtual int classDeclaration(Node *n) { +    return Language::classDeclaration(n); +  } + +  virtual int classHandler(Node *n) { +    have_constructor = 0; +    have_destructor = 0; +    constructor_name = 0; + +    class_name = Getattr(n, "sym:name"); + +    if (!addSymbol(class_name, n)) +      return SWIG_ERROR; + +    // This is a bug, due to the fact that swig_type -> octave_class mapping +    // is 1-to-n. +    static Hash *emitted = NewHash(); +    String *mangled_classname = Swig_name_mangle(Getattr(n, "name")); +    if (Getattr(emitted, mangled_classname)) { +      Delete(mangled_classname); +      return SWIG_NOWRAP; +    } +    Setattr(emitted, mangled_classname, "1"); +    Delete(mangled_classname); + +    assert(!s_members_tab); +    s_members_tab = NewString(""); +    Printv(s_members_tab, "static swig_octave_member swig_", class_name, "_members[] = {\n", NIL); + +    Language::classHandler(n); + +    SwigType *t = Copy(Getattr(n, "name")); +    SwigType_add_pointer(t); + +    // Replace storing a pointer to underlying class with a smart pointer (intended for use with non-intrusive smart pointers) +    SwigType *smart = Swig_cparse_smartptr(n); +    String *wrap_class = NewStringf("&_wrap_class_%s", class_name); +    if (smart) { +      SwigType_add_pointer(smart); +      SwigType_remember_clientdata(smart, wrap_class); +    } +    //String *wrap_class = NewStringf("&_wrap_class_%s", class_name); +    SwigType_remember_clientdata(t, wrap_class); + +    int use_director = Swig_directorclass(n); +    if (use_director) { +      String *nspace = Getattr(n, "sym:nspace"); +      String *cname = Swig_name_disown(nspace, class_name); +      String *wcname = Swig_name_wrapper(cname); +      String *cnameshdw = NewStringf("%s_shadow", cname); +      String *wcnameshdw = Swig_name_wrapper(cnameshdw); +      Octave_begin_function(n, f_wrappers, cnameshdw, wcnameshdw, true); +      Printf(f_wrappers, "  if (args.length()!=1) {\n"); +      Printf(f_wrappers, "    error(\"disown takes no arguments\");\n"); +      Printf(f_wrappers, "    return octave_value_list();\n"); +      Printf(f_wrappers, "  }\n"); +      Printf(f_wrappers, "  %s (args, nargout);\n", wcname); +      Printf(f_wrappers, "  return args;\n"); +      Printf(f_wrappers, "}\n"); +      Printf(s_members_tab, "{\"__disown\",%s,0,0,0,0},\n", wcnameshdw); +      Delete(wcname); +      Delete(cname); +      Delete(wcnameshdw); +      Delete(cnameshdw); +    } + +    Printf(s_members_tab, "{0,0,0,0,0,0}\n};\n"); +    Printv(f_wrappers, s_members_tab, NIL); + +    String *base_class_names = NewString(""); +    String *base_class = NewString(""); +    List *baselist = Getattr(n, "bases"); +    if (baselist && Len(baselist)) { +      Iterator b; +      b = First(baselist); +      while (b.item) { +        String *bname = Getattr(b.item, "name"); +        if ((!bname) || GetFlag(b.item, "feature:ignore") || (!Getattr(b.item, "module"))) { +          b = Next(b); +          continue; +        } + +        String *bname_mangled = SwigType_manglestr(SwigType_add_pointer(Copy(bname))); +        Printf(base_class_names, "\"%s\",", bname_mangled); +        Printf(base_class, "0,"); +        b = Next(b); +        Delete(bname_mangled); +      } +    } + +    Printv(f_wrappers, "static const char *swig_", class_name, "_base_names[] = {", base_class_names, "0};\n", NIL); +    Printv(f_wrappers, "static const swig_type_info *swig_", class_name, "_base[] = {", base_class, "0};\n", NIL); +    Printv(f_wrappers, "static swig_octave_class _wrap_class_", class_name, " = {\"", class_name, "\", &SWIGTYPE", SwigType_manglestr(t), ",", NIL); +    Printv(f_wrappers, Swig_directorclass(n) ? "1," : "0,", NIL); +    if (have_constructor) { +      String *nspace = Getattr(n, "sym:nspace"); +      String *cname = Swig_name_construct(nspace, constructor_name); +      String *wcname = Swig_name_wrapper(cname); +      String *tname = texinfo_name(n); +      Printf(f_wrappers, "%s,%s,", wcname, tname); +      Delete(tname); +      Delete(wcname); +      Delete(cname); +    } else +      Printv(f_wrappers, "0,0,", NIL); +    if (have_destructor) { +      String *nspace = Getattr(n, "sym:nspace"); +      String *cname = Swig_name_destroy(nspace, class_name); +      String *wcname = Swig_name_wrapper(cname); +      Printf(f_wrappers, "%s,", wcname); +      Delete(wcname); +      Delete(cname); +    } else +      Printv(f_wrappers, "0", ",", NIL); +    Printf(f_wrappers, "swig_%s_members,swig_%s_base_names,swig_%s_base };\n\n", class_name, class_name, class_name); + +    Delete(base_class); +    Delete(base_class_names); +    Delete(smart); +    Delete(t); +    Delete(s_members_tab); +    s_members_tab = 0; +    class_name = 0; + +    return SWIG_OK; +  } + +  virtual int memberfunctionHandler(Node *n) { +    Language::memberfunctionHandler(n); + +    assert(s_members_tab); +    assert(class_name); +    String *name = Getattr(n, "name"); +    String *iname = GetChar(n, "sym:name"); +    String *realname = iname ? iname : name; +    String *wname = Getattr(n, "wrap:name"); +    assert(wname); + +    if (!Getattr(n, "sym:nextSibling")) { +      String *tname = texinfo_name(n); +      String *rname = Copy(wname); +      bool overloaded = !!Getattr(n, "sym:overloaded"); +      if (overloaded) +        Delslice(rname, Len(rname) - Len(Getattr(n, "sym:overname")), DOH_END); +      Printf(s_members_tab, "{\"%s\",%s,0,0,0,%s},\n", +             realname, rname, tname); +      Delete(rname); +      Delete(tname); +    } + +    return SWIG_OK; +  } + +  virtual int membervariableHandler(Node *n) { +    Setattr(n, "feature:autodoc", "0"); + +    Language::membervariableHandler(n); + +    assert(s_members_tab); +    assert(class_name); +    String *symname = Getattr(n, "sym:name"); +    String *getname = Swig_name_get(NSPACE_TODO, Swig_name_member(NSPACE_TODO, class_name, symname)); +    String *setname = Swig_name_set(NSPACE_TODO, Swig_name_member(NSPACE_TODO, class_name, symname)); +    String *getwname = Swig_name_wrapper(getname); +    String *setwname = GetFlag(n, "feature:immutable") ? NewString("octave_set_immutable") : Swig_name_wrapper(setname); +    assert(s_members_tab); + +    Printf(s_members_tab, "{\"%s\",0,%s,%s,0,0},\n", symname, getwname, setwname); + +    Delete(getname); +    Delete(setname); +    Delete(getwname); +    Delete(setwname); +    return SWIG_OK; +  } + +  virtual int constructorHandler(Node *n) { +    have_constructor = 1; +    if (!constructor_name) +      constructor_name = NewString(Getattr(n, "sym:name")); + +    int use_director = Swig_directorclass(n); +    if (use_director) { +      Parm *parms = Getattr(n, "parms"); +      Parm *self; +      String *name = NewString("self"); +      String *type = NewString("void"); +      SwigType_add_pointer(type); +      self = NewParm(type, name, n); +      Delete(type); +      Delete(name); +      Setattr(self, "lname", "self_obj"); +      if (parms) +        set_nextSibling(self, parms); +      Setattr(n, "parms", self); +      Setattr(n, "wrap:self", "1"); +      Setattr(n, "hidden", "1"); +      Delete(self); +    } + +    return Language::constructorHandler(n); +  } + +  virtual int destructorHandler(Node *n) { +    have_destructor = 1; +    return Language::destructorHandler(n); +  } + +  virtual int staticmemberfunctionHandler(Node *n) { +    Language::staticmemberfunctionHandler(n); + +    assert(s_members_tab); +    assert(class_name); +    String *name = Getattr(n, "name"); +    String *iname = GetChar(n, "sym:name"); +    String *realname = iname ? iname : name; +    String *wname = Getattr(n, "wrap:name"); +    assert(wname); + +    if (!Getattr(n, "sym:nextSibling")) { +      String *tname = texinfo_name(n); +      String *rname = Copy(wname); +      bool overloaded = !!Getattr(n, "sym:overloaded"); +      if (overloaded) +        Delslice(rname, Len(rname) - Len(Getattr(n, "sym:overname")), DOH_END); +      Printf(s_members_tab, "{\"%s\",%s,0,0,1,%s},\n", +             realname, rname, tname); +      Delete(rname); +      Delete(tname); +    } + +    return SWIG_OK; +  } + +  virtual int memberconstantHandler(Node *n) { +    return Language::memberconstantHandler(n); +  } + +  virtual int staticmembervariableHandler(Node *n) { +    Setattr(n, "feature:autodoc", "0"); + +    Language::staticmembervariableHandler(n); + +    if (!GetFlag(n, "wrappedasconstant")) { +      assert(s_members_tab); +      assert(class_name); +      String *symname = Getattr(n, "sym:name"); +      String *getname = Swig_name_get(NSPACE_TODO, Swig_name_member(NSPACE_TODO, class_name, symname)); +      String *setname = Swig_name_set(NSPACE_TODO, Swig_name_member(NSPACE_TODO, class_name, symname)); +      String *getwname = Swig_name_wrapper(getname); +      String *setwname = GetFlag(n, "feature:immutable") ? NewString("octave_set_immutable") : Swig_name_wrapper(setname); +      assert(s_members_tab); + +      Printf(s_members_tab, "{\"%s\",0,%s,%s,1,0},\n", symname, getwname, setwname); + +      Delete(getname); +      Delete(setname); +      Delete(getwname); +      Delete(setwname); +    } +    return SWIG_OK; +  } + +  int classDirectorInit(Node *n) { +    String *declaration = Swig_director_declaration(n); +    Printf(f_directors_h, "\n"); +    Printf(f_directors_h, "%s\n", declaration); +    Printf(f_directors_h, "public:\n"); +    Delete(declaration); +    return Language::classDirectorInit(n); +  } + +  int classDirectorEnd(Node *n) { +    Printf(f_directors_h, "};\n\n"); +    return Language::classDirectorEnd(n); +  } + +  int classDirectorConstructor(Node *n) { +    Node *parent = Getattr(n, "parentNode"); +    String *sub = NewString(""); +    String *decl = Getattr(n, "decl"); +    String *supername = Swig_class_name(parent); +    String *classname = NewString(""); +    Printf(classname, "SwigDirector_%s", supername); + +    // insert self parameter +    Parm *p; +    ParmList *superparms = Getattr(n, "parms"); +    ParmList *parms = CopyParmList(superparms); +    String *type = NewString("void"); +    SwigType_add_pointer(type); +    p = NewParm(type, NewString("self"), n); +    set_nextSibling(p, parms); +    parms = p; + +    if (!Getattr(n, "defaultargs")) { +      // constructor +      { +        Wrapper *w = NewWrapper(); +        String *call; +        String *basetype = Getattr(parent, "classtype"); +        String *target = Swig_method_decl(0, decl, classname, parms, 0); +        call = Swig_csuperclass_call(0, basetype, superparms); +        Printf(w->def, "%s::%s: %s," "\nSwig::Director(static_cast<%s*>(this)) { \n", classname, target, call, basetype); +        Append(w->def, "}\n"); +        Delete(target); +        Wrapper_print(w, f_directors); +        Delete(call); +        DelWrapper(w); +      } + +      // constructor header +      { +        String *target = Swig_method_decl(0, decl, classname, parms, 1); +        Printf(f_directors_h, "    %s;\n", target); +        Delete(target); +      } +    } + +    Delete(sub); +    Delete(classname); +    Delete(supername); +    Delete(parms); +    return Language::classDirectorConstructor(n); +  } + +  int classDirectorDefaultConstructor(Node *n) { +    String *classname = Swig_class_name(n); +    { +      Wrapper *w = NewWrapper(); +      Printf(w->def, "SwigDirector_%s::SwigDirector_%s(void* self) :" +             "\nSwig::Director((octave_swig_type*)self,static_cast<%s*>(this)) { \n", classname, classname, classname); +      Append(w->def, "}\n"); +      Wrapper_print(w, f_directors); +      DelWrapper(w); +    } +    Printf(f_directors_h, "    SwigDirector_%s(octave_swig_type* self);\n", classname); +    Delete(classname); +    return Language::classDirectorDefaultConstructor(n); +  } + +  int classDirectorMethod(Node *n, Node *parent, String *super) { +    int is_void = 0; +    int is_pointer = 0; +    String *decl = Getattr(n, "decl"); +    String *returntype = Getattr(n, "type"); +    String *name = Getattr(n, "name"); +    String *classname = Getattr(parent, "sym:name"); +    String *c_classname = Getattr(parent, "name"); +    String *symname = Getattr(n, "sym:name"); +    String *declaration = NewString(""); +    ParmList *l = Getattr(n, "parms"); +    Wrapper *w = NewWrapper(); +    String *tm; +    String *wrap_args = NewString(""); +    String *value = Getattr(n, "value"); +    String *storage = Getattr(n, "storage"); +    bool pure_virtual = false; +    int status = SWIG_OK; +    int idx; +    bool ignored_method = GetFlag(n, "feature:ignore") ? true : false; + +    if (Cmp(storage, "virtual") == 0) { +      if (Cmp(value, "0") == 0) { +        pure_virtual = true; +      } +    } + +    // determine if the method returns a pointer +    is_pointer = SwigType_ispointer_return(decl); +    is_void = (!Cmp(returntype, "void") && !is_pointer); + +    // virtual method definition +    String *target; +    String *pclassname = NewStringf("SwigDirector_%s", classname); +    String *qualified_name = NewStringf("%s::%s", pclassname, name); +    SwigType *rtype = Getattr(n, "conversion_operator") ? 0 : Getattr(n, "classDirectorMethods:type"); +    target = Swig_method_decl(rtype, decl, qualified_name, l, 0); +    Printf(w->def, "%s", target); +    Delete(qualified_name); +    Delete(target); + +    // header declaration +    target = Swig_method_decl(rtype, decl, name, l, 1); +    Printf(declaration, "    virtual %s", target); +    Delete(target); + +    // Get any exception classes in the throws typemap +    if (Getattr(n, "noexcept")) { +      Append(w->def, " noexcept"); +      Append(declaration, " noexcept"); +    } +    ParmList *throw_parm_list = 0; + +    if ((throw_parm_list = Getattr(n, "throws")) || Getattr(n, "throw")) { +      Parm *p; +      int gencomma = 0; + +      Append(w->def, " throw("); +      Append(declaration, " throw("); + +      if (throw_parm_list) +        Swig_typemap_attach_parms("throws", throw_parm_list, 0); +      for (p = throw_parm_list; p; p = nextSibling(p)) { +        if (Getattr(p, "tmap:throws")) { +          if (gencomma++) { +            Append(w->def, ", "); +            Append(declaration, ", "); +          } +          String *str = SwigType_str(Getattr(p, "type"), 0); +          Append(w->def, str); +          Append(declaration, str); +          Delete(str); +        } +      } + +      Append(w->def, ")"); +      Append(declaration, ")"); +    } + +    Append(w->def, " {"); +    Append(declaration, ";\n"); + +    // declare method return value +    // if the return value is a reference or const reference, a specialized typemap must +    // handle it, including declaration of c_result ($result). +    if (!is_void && (!ignored_method || pure_virtual)) { +      if (!SwigType_isclass(returntype)) { +	if (!(SwigType_ispointer(returntype) || SwigType_isreference(returntype))) { +	  String *construct_result = NewStringf("= SwigValueInit< %s >()", SwigType_lstr(returntype, 0)); +	  Wrapper_add_localv(w, "c_result", SwigType_lstr(returntype, "c_result"), construct_result, NIL); +	  Delete(construct_result); +	} else { +	  Wrapper_add_localv(w, "c_result", SwigType_lstr(returntype, "c_result"), "= 0", NIL); +	} +      } else { +	String *cres = SwigType_lstr(returntype, "c_result"); +	Printf(w->code, "%s;\n", cres); +	Delete(cres); +      } +    } + +    if (ignored_method) { +      if (!pure_virtual) { +        if (!is_void) +          Printf(w->code, "return "); +        String *super_call = Swig_method_call(super, l); +        Printf(w->code, "%s;\n", super_call); +        Delete(super_call); +      } else { +        Printf(w->code, "Swig::DirectorPureVirtualException::raise(\"Attempted to invoke pure virtual method %s::%s\");\n", SwigType_namestr(c_classname), +               SwigType_namestr(name)); +      } +    } else { +      // attach typemaps to arguments (C/C++ -> Octave) +      String *parse_args = NewString(""); + +      Swig_director_parms_fixup(l); + +      Swig_typemap_attach_parms("in", l, 0); +      Swig_typemap_attach_parms("directorin", l, w); +      Swig_typemap_attach_parms("directorargout", l, w); + +      Parm *p; + +      int outputs = 0; +      if (!is_void) +        outputs++; + +      // build argument list and type conversion string +      p = l; +      while (p) { +        if (checkAttribute(p, "tmap:in:numinputs", "0")) { +          p = Getattr(p, "tmap:in:next"); +          continue; +        } + +        if (Getattr(p, "tmap:directorargout") != 0) +          outputs++; + +        String *pname = Getattr(p, "name"); +        String *ptype = Getattr(p, "type"); +        Wrapper_add_local(w, "tmpv", "octave_value tmpv"); + +        if ((tm = Getattr(p, "tmap:directorin")) != 0) { +          String *parse = Getattr(p, "tmap:directorin:parse"); +          if (!parse) { +            Setattr(p, "emit:directorinput", "tmpv"); +            Replaceall(tm, "$input", "tmpv"); +            Replaceall(tm, "$owner", "0"); +            Printv(wrap_args, tm, "\n", NIL); +            Printf(wrap_args, "args.append(tmpv);\n"); +            Putc('O', parse_args); +          } else { +            Append(parse_args, parse); +            Setattr(p, "emit:directorinput", pname); +            Replaceall(tm, "$input", pname); +            Replaceall(tm, "$owner", "0"); +            if (Len(tm) == 0) +              Append(tm, pname); +          } +          p = Getattr(p, "tmap:directorin:next"); +          continue; +        } else if (Cmp(ptype, "void")) { +          Swig_warning(WARN_TYPEMAP_DIRECTORIN_UNDEF, input_file, line_number, +                       "Unable to use type %s as a function argument in director method %s::%s (skipping method).\n", SwigType_str(ptype, 0), +                       SwigType_namestr(c_classname), SwigType_namestr(name)); +          status = SWIG_NOWRAP; +          break; +        } +        p = nextSibling(p); +      } + +      String *method_name = Getattr(n, "sym:name"); + +      Printv(w->code, wrap_args, NIL); + +      // emit method invocation +      Wrapper_add_local(w, "args", "octave_value_list args"); +      Wrapper_add_local(w, "out", "octave_value_list out"); +      Wrapper_add_local(w, "idx", "std::list<octave_value_list> idx"); +      Printf(w->code, "idx.push_back(octave_value_list(\"%s\"));\n", method_name); +      Printf(w->code, "idx.push_back(args);\n"); +      Printf(w->code, "out=swig_get_self()->subsref(\".(\",idx,%d);\n", outputs); + +      String *cleanup = NewString(""); +      String *outarg = NewString(""); +      idx = 0; + +      // marshal return value +      if (!is_void) { +        Printf(w->code, "if (out.length()<%d) {\n", outputs); +        Printf(w->code, "Swig::DirectorTypeMismatchException::raise(\"Octave " +               "method %s.%s failed to return the required number " "of arguments.\");\n", classname, method_name); +        Printf(w->code, "}\n"); + +        tm = Swig_typemap_lookup("directorout", n, Swig_cresult_name(), w); +        if (tm != 0) { +          char temp[24]; +          sprintf(temp, "out(%d)", idx); +          Replaceall(tm, "$input", temp); +          //    Replaceall(tm, "$argnum", temp); +          Replaceall(tm, "$disown", Getattr(n, "wrap:disown") ? "SWIG_POINTER_DISOWN" : "0"); +          if (Getattr(n, "tmap:directorout:implicitconv")) { +            Replaceall(tm, "$implicitconv", get_implicitconv_flag(n)); +          } +          Replaceall(tm, "$result", "c_result"); +          Printv(w->code, tm, "\n", NIL); +          Delete(tm); +        } else { +          Swig_warning(WARN_TYPEMAP_DIRECTOROUT_UNDEF, input_file, line_number, +                       "Unable to use return type %s in director method %s::%s (skipping method).\n", +                       SwigType_str(returntype, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); +          status = SWIG_ERROR; +        } +      } +      idx++; + +      // marshal outputs +      for (p = l; p;) { +        if ((tm = Getattr(p, "tmap:directorargout")) != 0) { +          char temp[24]; +          sprintf(temp, "out(%d)", idx); +          Replaceall(tm, "$result", temp); +          Replaceall(tm, "$input", Getattr(p, "emit:directorinput")); +          Printv(w->code, tm, "\n", NIL); +          p = Getattr(p, "tmap:directorargout:next"); +        } else { +          p = nextSibling(p); +        } +      } + +      Delete(parse_args); +      Delete(cleanup); +      Delete(outarg); +    } + +    if (!is_void) { +      if (!(ignored_method && !pure_virtual)) { +        String *rettype = SwigType_str(returntype, 0); +        if (!SwigType_isreference(returntype)) { +          Printf(w->code, "return (%s) c_result;\n", rettype); +        } else { +          Printf(w->code, "return (%s) *c_result;\n", rettype); +        } +        Delete(rettype); +      } +    } + +    Append(w->code, "}\n"); + +    // We expose protected methods via an extra public inline method which makes a straight call to the wrapped class' method +    String *inline_extra_method = NewString(""); +    if (dirprot_mode() && !is_public(n) && !pure_virtual) { +      Printv(inline_extra_method, declaration, NIL); +      String *extra_method_name = NewStringf("%sSwigPublic", name); +      Replaceall(inline_extra_method, name, extra_method_name); +      Replaceall(inline_extra_method, ";\n", " {\n      "); +      if (!is_void) +        Printf(inline_extra_method, "return "); +      String *methodcall = Swig_method_call(super, l); +      Printv(inline_extra_method, methodcall, ";\n    }\n", NIL); +      Delete(methodcall); +      Delete(extra_method_name); +    } +    // emit the director method +    if (status == SWIG_OK) { +      if (!Getattr(n, "defaultargs")) { +        Replaceall(w->code, "$symname", symname); +        Wrapper_print(w, f_directors); +        Printv(f_directors_h, declaration, NIL); +        Printv(f_directors_h, inline_extra_method, NIL); +      } +    } +    // clean up +    Delete(wrap_args); +    Delete(pclassname); +    DelWrapper(w); +    return status; +  } + +  String *runtimeCode() { +    String *s = NewString(""); +    String *srun = Swig_include_sys("octrun.swg"); +    if (!srun) { +      Printf(stderr, "*** Unable to open 'octrun.swg'\n"); +    } else { +      Append(s, srun); +      Delete(srun); +    } +    return s; +  } + +  String *defaultExternalRuntimeFilename() { +    return NewString("swigoctaverun.h"); +  } +}; + +extern "C" Language *swig_octave(void) { +  return new OCTAVE(); +} diff --git a/contrib/tools/swig/Source/Modules/overload.cxx b/contrib/tools/swig/Source/Modules/overload.cxx new file mode 100644 index 00000000000..b94e87ebb71 --- /dev/null +++ b/contrib/tools/swig/Source/Modules/overload.cxx @@ -0,0 +1,866 @@ +/* -----------------------------------------------------------------------------  + * This file is part of SWIG, which is licensed as a whole under version 3  + * (or any later version) of the GNU General Public License. Some additional + * terms also apply to certain portions of SWIG. The full details of the SWIG + * license and copyrights can be found in the LICENSE and COPYRIGHT files + * included with the SWIG source code as distributed by the SWIG developers + * and at https://www.swig.org/legal.html. + * + * overload.cxx + * + * This file is used to analyze overloaded functions and methods. + * It looks at signatures and tries to gather information for + * building a dispatch function. + * ----------------------------------------------------------------------------- */ + +#include "swigmod.h" + +#define MAX_OVERLOAD 4096 + +/* Overload "argc" and "argv" */ +String *argv_template_string; +String *argc_template_string; + +namespace { +struct Overloaded { +  Node *n;			/* Node                               */ +  int argc;			/* Argument count                     */ +  ParmList *parms;		/* Parameters used for overload check */ +  int error;			/* Ambiguity error                    */ +  bool implicitconv_function;	/* For ordering implicitconv functions*/ +}; +} + +static int fast_dispatch_mode = 0; +static int cast_dispatch_mode = 0; + +/* Set fast_dispatch_mode */ +void Wrapper_fast_dispatch_mode_set(int flag) { +  fast_dispatch_mode = flag; +} + +void Wrapper_cast_dispatch_mode_set(int flag) { +  cast_dispatch_mode = flag; +} + +/* ----------------------------------------------------------------------------- + * mark_implicitconv_function() + * + * Mark function if it contains an implicitconv type in the parameter list + * ----------------------------------------------------------------------------- */ +static void mark_implicitconv_function(Overloaded& onode) { +  Parm *parms = onode.parms; +  if (parms) { +    bool is_implicitconv_function = false; +    Parm *p = parms; +    while (p) { +      if (checkAttribute(p, "tmap:in:numinputs", "0")) { +	p = Getattr(p, "tmap:in:next"); +	continue; +      } +      if (GetFlag(p, "implicitconv")) { +	is_implicitconv_function = true; +	break; +      } +      p = nextSibling(p); +    } +    if (is_implicitconv_function) +      onode.implicitconv_function = true; +  } +} + +/* ----------------------------------------------------------------------------- + * Swig_overload_rank() + * + * This function takes an overloaded declaration and creates a list that ranks + * all overloaded methods in an order that can be used to generate a dispatch  + * function. + * Slight difference in the way this function is used by scripting languages and + * statically typed languages. The script languages call this method via  + * Swig_overload_dispatch() - where wrappers for all overloaded methods are generated, + * however sometimes the code can never be executed. The non-scripting languages + * call this method via Swig_overload_check() for each overloaded method in order + * to determine whether or not the method should be wrapped. Note the slight + * difference when overloading methods that differ by const only. The + * scripting languages will ignore the const method, whereas the non-scripting + * languages ignore the first method parsed. + * ----------------------------------------------------------------------------- */ + +List *Swig_overload_rank(Node *n, bool script_lang_wrapping) { +  Overloaded nodes[MAX_OVERLOAD]; +  int nnodes = 0; +  Node *o = Getattr(n, "sym:overloaded"); +  Node *c; + +  if (!o) +    return 0; + +  c = o; +  while (c) { +    if (Getattr(c, "error")) { +      c = Getattr(c, "sym:nextSibling"); +      continue; +    } +    /*    if (SmartPointer && Getattr(c,"cplus:staticbase")) { +       c = Getattr(c,"sym:nextSibling"); +       continue; +       } */ + +    /* Make a list of all the declarations (methods) that are overloaded with +     * this one particular method name */ +    if (Getattr(c, "wrap:name")) { +      assert(nnodes < MAX_OVERLOAD); +      nodes[nnodes].n = c; +      nodes[nnodes].parms = Getattr(c, "wrap:parms"); +      nodes[nnodes].argc = emit_num_required(nodes[nnodes].parms); +      nodes[nnodes].error = 0; +      nodes[nnodes].implicitconv_function = false; + +      mark_implicitconv_function(nodes[nnodes]); +      nnodes++; +    } +    c = Getattr(c, "sym:nextSibling"); +  } + +  /* Sort the declarations by required argument count */ +  { +    int i, j; +    for (i = 0; i < nnodes; i++) { +      for (j = i + 1; j < nnodes; j++) { +	if (nodes[i].argc > nodes[j].argc) { +	  Overloaded t = nodes[i]; +	  nodes[i] = nodes[j]; +	  nodes[j] = t; +	} +      } +    } +  } + +  /* Sort the declarations by argument types */ +  { +    int i, j; +    for (i = 0; i < nnodes - 1; i++) { +      if (nodes[i].argc == nodes[i + 1].argc) { +	for (j = i + 1; (j < nnodes) && (nodes[j].argc == nodes[i].argc); j++) { +	  Parm *p1 = nodes[i].parms; +	  Parm *p2 = nodes[j].parms; +	  int differ = 0; +	  int num_checked = 0; +	  while (p1 && p2 && (num_checked < nodes[i].argc)) { +	    //    Printf(stdout,"p1 = '%s', p2 = '%s'\n", Getattr(p1,"type"), Getattr(p2,"type")); +	    if (checkAttribute(p1, "tmap:in:numinputs", "0")) { +	      p1 = Getattr(p1, "tmap:in:next"); +	      continue; +	    } +	    if (checkAttribute(p2, "tmap:in:numinputs", "0")) { +	      p2 = Getattr(p2, "tmap:in:next"); +	      continue; +	    } +	    String *t1 = Getattr(p1, "tmap:typecheck:precedence"); +	    String *t2 = Getattr(p2, "tmap:typecheck:precedence"); +	    if ((!t1) && (!nodes[i].error)) { +	      Swig_warning(WARN_TYPEMAP_TYPECHECK, Getfile(nodes[i].n), Getline(nodes[i].n), +			   "Overloaded method %s not supported (incomplete type checking rule - no precedence level in typecheck typemap for '%s').\n", +			   Swig_name_decl(nodes[i].n), SwigType_str(Getattr(p1, "type"), 0)); +	      nodes[i].error = 1; +	    } else if ((!t2) && (!nodes[j].error)) { +	      Swig_warning(WARN_TYPEMAP_TYPECHECK, Getfile(nodes[j].n), Getline(nodes[j].n), +			   "Overloaded method %s not supported (incomplete type checking rule - no precedence level in typecheck typemap for '%s').\n", +			   Swig_name_decl(nodes[j].n), SwigType_str(Getattr(p2, "type"), 0)); +	      nodes[j].error = 1; +	    } +	    if (t1 && t2) { +	      int t1v, t2v; +	      t1v = atoi(Char(t1)); +	      t2v = atoi(Char(t2)); +	      differ = t1v - t2v; +	    } else if (!t1 && t2) +	      differ = 1; +	    else if (t1 && !t2) +	      differ = -1; +	    else if (!t1 && !t2) +	      differ = -1; +	    num_checked++; +	    if (differ > 0) { +	      Overloaded t = nodes[i]; +	      nodes[i] = nodes[j]; +	      nodes[j] = t; +	      break; +	    } else if ((differ == 0) && (Strcmp(t1, "0") == 0)) { +	      t1 = Getattr(p1, "equivtype"); +	      t1 = t1 ? t1 : Getattr(p1, "ltype"); +	      if (!t1) { +		t1 = SwigType_ltype(Getattr(p1, "type")); +		if (Getattr(p1, "tmap:typecheck:SWIGTYPE")) { +		  SwigType_add_pointer(t1); +		} +		Setattr(p1, "ltype", t1); +	      } +	      t2 = Getattr(p2, "equivtype"); +	      t2 = t2 ? t2 : Getattr(p2, "ltype"); +	      if (!t2) { +		t2 = SwigType_ltype(Getattr(p2, "type")); +		if (Getattr(p2, "tmap:typecheck:SWIGTYPE")) { +		  SwigType_add_pointer(t2); +		} +		Setattr(p2, "ltype", t2); +	      } + +	      /* Need subtype check here.  If t2 is a subtype of t1, then we need to change the +	         order */ + +	      if (SwigType_issubtype(t2, t1)) { +		Overloaded t = nodes[i]; +		nodes[i] = nodes[j]; +		nodes[j] = t; +	      } + +	      if (Strcmp(t1, t2) != 0) { +		differ = 1; +		break; +	      } +	    } else if (differ) { +	      break; +	    } +	    if (Getattr(p1, "tmap:in:next")) { +	      p1 = Getattr(p1, "tmap:in:next"); +	    } else { +	      p1 = nextSibling(p1); +	    } +	    if (Getattr(p2, "tmap:in:next")) { +	      p2 = Getattr(p2, "tmap:in:next"); +	    } else { +	      p2 = nextSibling(p2); +	    } +	  } +	  if (!differ) { +	    /* See if declarations differ by const only */ +	    String *decl1 = Getattr(nodes[i].n, "decl"); +	    String *decl2 = Getattr(nodes[j].n, "decl"); +	    if (decl1 && decl2) { +	      /* Remove ref-qualifiers. Note that rvalue ref-qualifiers are already ignored and  +	       * it is illegal to overload a function with and without ref-qualifiers. So with +	       * all the combinations of ref-qualifiers and cv-qualifiers, we just detect  +	       * the cv-qualifier (const) overloading. */ +	      String *d1 = Copy(decl1); +	      String *d2 = Copy(decl2); +	      if (SwigType_isreference(d1) || SwigType_isrvalue_reference(d1)) { +		Delete(SwigType_pop(d1)); +	      } +	      if (SwigType_isreference(d2) || SwigType_isrvalue_reference(d2)) { +		Delete(SwigType_pop(d2)); +	      } +	      String *dq1 = Copy(d1); +	      String *dq2 = Copy(d2); +	      if (SwigType_isconst(d1)) { +		Delete(SwigType_pop(dq1)); +	      } +	      if (SwigType_isconst(d2)) { +		Delete(SwigType_pop(dq2)); +	      } +	      if (Strcmp(dq1, dq2) == 0) { + +		if (SwigType_isconst(d1) && !SwigType_isconst(d2)) { +		  if (script_lang_wrapping) { +		    // Swap nodes so that the const method gets ignored (shadowed by the non-const method) +		    Overloaded t = nodes[i]; +		    nodes[i] = nodes[j]; +		    nodes[j] = t; +		  } +		  differ = 1; +		  if (!nodes[j].error) { +		    if (script_lang_wrapping) { +		      Swig_warning(WARN_LANG_OVERLOAD_CONST, Getfile(nodes[j].n), Getline(nodes[j].n), +				   "Overloaded method %s ignored,\n", Swig_name_decl(nodes[j].n)); +		      Swig_warning(WARN_LANG_OVERLOAD_CONST, Getfile(nodes[i].n), Getline(nodes[i].n), +				   "using non-const method %s instead.\n", Swig_name_decl(nodes[i].n)); +		    } else { +		      if (!Getattr(nodes[j].n, "overload:ignore")) { +			Swig_warning(WARN_LANG_OVERLOAD_IGNORED, Getfile(nodes[j].n), Getline(nodes[j].n), +				     "Overloaded method %s ignored,\n", Swig_name_decl(nodes[j].n)); +			Swig_warning(WARN_LANG_OVERLOAD_IGNORED, Getfile(nodes[i].n), Getline(nodes[i].n), +				     "using %s instead.\n", Swig_name_decl(nodes[i].n)); +		      } +		    } +		  } +		  nodes[j].error = 1; +		} else if (!SwigType_isconst(d1) && SwigType_isconst(d2)) { +		  differ = 1; +		  if (!nodes[j].error) { +		    if (script_lang_wrapping) { +		      Swig_warning(WARN_LANG_OVERLOAD_CONST, Getfile(nodes[j].n), Getline(nodes[j].n), +				   "Overloaded method %s ignored,\n", Swig_name_decl(nodes[j].n)); +		      Swig_warning(WARN_LANG_OVERLOAD_CONST, Getfile(nodes[i].n), Getline(nodes[i].n), +				   "using non-const method %s instead.\n", Swig_name_decl(nodes[i].n)); +		    } else { +		      if (!Getattr(nodes[j].n, "overload:ignore")) { +			Swig_warning(WARN_LANG_OVERLOAD_IGNORED, Getfile(nodes[j].n), Getline(nodes[j].n), +				     "Overloaded method %s ignored,\n", Swig_name_decl(nodes[j].n)); +			Swig_warning(WARN_LANG_OVERLOAD_IGNORED, Getfile(nodes[i].n), Getline(nodes[i].n), +				     "using %s instead.\n", Swig_name_decl(nodes[i].n)); +		      } +		    } +		  } +		  nodes[j].error = 1; +		} +	      } +	      Delete(dq1); +	      Delete(dq2); +	    } +	  } +	  if (!differ) { +	    if (!nodes[j].error) { +	      if (script_lang_wrapping) { +		Swig_warning(WARN_LANG_OVERLOAD_SHADOW, Getfile(nodes[j].n), Getline(nodes[j].n), +			     "Overloaded method %s effectively ignored,\n", Swig_name_decl(nodes[j].n)); +		Swig_warning(WARN_LANG_OVERLOAD_SHADOW, Getfile(nodes[i].n), Getline(nodes[i].n), +			     "as it is shadowed by %s.\n", Swig_name_decl(nodes[i].n)); +	      } else { +		if (!Getattr(nodes[j].n, "overload:ignore")) { +		  Swig_warning(WARN_LANG_OVERLOAD_IGNORED, Getfile(nodes[j].n), Getline(nodes[j].n), +			       "Overloaded method %s ignored,\n", Swig_name_decl(nodes[j].n)); +		  Swig_warning(WARN_LANG_OVERLOAD_IGNORED, Getfile(nodes[i].n), Getline(nodes[i].n), +			       "using %s instead.\n", Swig_name_decl(nodes[i].n)); +		} +	      } +	      nodes[j].error = 1; +	    } +	  } +	} +      } +    } +  } +  List *result = NewList(); +  { +    int i; +    int argc_changed_index = -1; +    for (i = 0; i < nnodes; i++) { +      if (nodes[i].error) +	Setattr(nodes[i].n, "overload:ignore", "1"); +      Append(result, nodes[i].n); +      // Printf(stdout,"[ %d ] %d    %s\n", i, nodes[i].implicitconv_function, ParmList_errorstr(nodes[i].parms)); +      if (i == nnodes-1 || nodes[i].argc != nodes[i+1].argc) { +	if (argc_changed_index+2 < nnodes && (nodes[argc_changed_index+1].argc == nodes[argc_changed_index+2].argc)) { +	  // Add additional implicitconv functions in same order as already ranked. +	  // Consider overloaded functions by argument count... only add additional implicitconv functions if +	  // the number of functions with the same arg count > 1, ie, only if overloaded by same argument count. +	  int j; +	  for (j = argc_changed_index + 1; j <= i; j++) { +	    if (nodes[j].implicitconv_function) { +	      SetFlag(nodes[j].n, "implicitconvtypecheckoff"); +	      Append(result, nodes[j].n); +	      // Printf(stdout,"[ %d ] %d +  %s\n", j, nodes[j].implicitconv_function, ParmList_errorstr(nodes[j].parms)); +	    } +	  } +	} +	argc_changed_index = i; +      } +    } +  } +  return result; +} + +// /* ----------------------------------------------------------------------------- +//  * print_typecheck() +//  * ----------------------------------------------------------------------------- */ + +static bool print_typecheck(String *f, int j, Parm *pj, bool implicitconvtypecheckoff) { +  char tmp[256]; +  sprintf(tmp, Char(argv_template_string), j); +  String *tm = Getattr(pj, "tmap:typecheck"); +  if (tm) { +    tm = Copy(tm); +    Replaceid(tm, Getattr(pj, "lname"), "_v"); +    String *conv = Getattr(pj, "implicitconv"); +    if (conv && !implicitconvtypecheckoff) { +      Replaceall(tm, "$implicitconv", conv); +    } else { +      Replaceall(tm, "$implicitconv", "0"); +    } +    Replaceall(tm, "$input", tmp); +    Printv(f, tm, "\n", NIL); +    Delete(tm); +    return true; +  } else +    return false; +} + +/* ----------------------------------------------------------------------------- + * ReplaceFormat() + * ----------------------------------------------------------------------------- */ + +static String *ReplaceFormat(const_String_or_char_ptr fmt, int j) { +  String *lfmt = NewString(fmt); +  char buf[50]; +  sprintf(buf, "%d", j); +  Replaceall(lfmt, "$numargs", buf); +  int i; +  String *commaargs = NewString(""); +  for (i = 0; i < j; i++) { +    Printv(commaargs, ", ", NIL); +    Printf(commaargs, Char(argv_template_string), i); +  } +  Replaceall(lfmt, "$commaargs", commaargs); +  return lfmt; +} + +/* ----------------------------------------------------------------------------- + * Swig_overload_dispatch() + * + * Generate a dispatch function.  argc is assumed to hold the argument count. + * argv is the argument vector. + * + * Note that for C++ class member functions, Swig_overload_dispatch() assumes + * that argc includes the "self" argument and that the first element of argv[] + * is the "self" argument. So for a member function: + * + *     Foo::bar(int x, int y, int z); + * + * the argc should be 4 (not 3!) and the first element of argv[] would be + * the appropriate scripting language reference to "self". For regular + * functions (and static class functions) the argc and argv only include + * the regular function arguments. + * ----------------------------------------------------------------------------- */ + +/* +  Cast dispatch mechanism. +*/ +String *Swig_overload_dispatch_cast(Node *n, const_String_or_char_ptr fmt, int *maxargs) { +  int i, j; + +  *maxargs = 1; + +  String *f = NewString(""); +  String *sw = NewString(""); +  Printf(f, "{\n"); +  Printf(f, "unsigned long _index = 0;\n"); +  Printf(f, "SWIG_TypeRank _rank = 0; \n"); + +  /* Get a list of methods ranked by precedence values and argument count */ +  List *dispatch = Swig_overload_rank(n, true); +  int nfunc = Len(dispatch); + +  /* Loop over the functions */ + +  bool emitcheck = true; +  for (i = 0; i < nfunc; i++) { +    int fn = 0; +    Node *ni = Getitem(dispatch, i); +    Parm *pi = Getattr(ni, "wrap:parms"); +    bool implicitconvtypecheckoff = GetFlag(ni, "implicitconvtypecheckoff") != 0; +    int num_required = emit_num_required(pi); +    int num_arguments = emit_num_arguments(pi); +    if (num_arguments > *maxargs) +      *maxargs = num_arguments; + +    if (num_required == num_arguments) { +      Printf(f, "if (%s == %d) {\n", argc_template_string, num_required); +    } else { +      Printf(f, "if ((%s >= %d) && (%s <= %d)) {\n", argc_template_string, num_required, argc_template_string, num_arguments); +    } +    Printf(f, "SWIG_TypeRank _ranki = 0;\n"); +    Printf(f, "SWIG_TypeRank _rankm = 0;\n"); +    if (num_arguments) +      Printf(f, "SWIG_TypeRank _pi = 1;\n"); + +    /* create a list with the wrappers that collide with the +       current one based on argument number */ +    List *coll = NewList(); +    for (int k = i + 1; k < nfunc; k++) { +      Node *nk = Getitem(dispatch, k); +      Parm *pk = Getattr(nk, "wrap:parms"); +      int nrk = emit_num_required(pk); +      int nak = emit_num_arguments(pk); +      if ((nrk >= num_required && nrk <= num_arguments) || (nak >= num_required && nak <= num_arguments) || (nrk <= num_required && nak >= num_arguments)) +	Append(coll, nk); +    } + +    // printf("overload: %s coll=%d\n", Char(Getattr(n, "sym:name")), Len(coll)); + +    int num_braces = 0; +    bool test = (num_arguments > 0); +    if (test) { +      int need_v = 1; +      j = 0; +      Parm *pj = pi; +      while (pj) { +	if (checkAttribute(pj, "tmap:in:numinputs", "0")) { +	  pj = Getattr(pj, "tmap:in:next"); +	  continue; +	} + +	String *tm = Getattr(pj, "tmap:typecheck"); +	if (tm) { +	  tm = Copy(tm); +	  /* normalise for comparison later */ +	  Replaceid(tm, Getattr(pj, "lname"), "_v"); + +	  /* if all the wrappers have the same type check on this +	     argument we can optimize it out */ +	  for (int k = 0; k < Len(coll) && !emitcheck; k++) { +	    Node *nk = Getitem(coll, k); +	    Parm *pk = Getattr(nk, "wrap:parms"); +	    int nak = emit_num_arguments(pk); +	    if (nak <= j) +	      continue; +	    int l = 0; +	    Parm *pl = pk; +	    /* finds arg j on the collider wrapper */ +	    while (pl && l <= j) { +	      if (checkAttribute(pl, "tmap:in:numinputs", "0")) { +		pl = Getattr(pl, "tmap:in:next"); +		continue; +	      } +	      if (l == j) { +		/* we are at arg j, so we compare the tmaps now */ +		String *tml = Getattr(pl, "tmap:typecheck"); +		/* normalise it before comparing */ +		if (tml) +		  Replaceid(tml, Getattr(pl, "lname"), "_v"); +		if (!tml || Cmp(tm, tml)) +		  emitcheck = true; +		//printf("tmap: %s[%d] (%d) => %s\n\n", +		//       Char(Getattr(nk, "sym:name")), +		//       l, emitcheck, tml?Char(tml):0); +	      } +	      Parm *pl1 = Getattr(pl, "tmap:in:next"); +	      if (pl1) +		pl = pl1; +	      else +		pl = nextSibling(pl); +	      l++; +	    } +	  } + +	  if (emitcheck) { +	    if (need_v) { +	      Printf(f, "int _v = 0;\n"); +	      need_v = 0; +	    } +	    if (j >= num_required) { +	      Printf(f, "if (%s > %d) {\n", argc_template_string, j); +	      num_braces++; +	    } +	    String *tmp = NewStringf(argv_template_string, j); + +	    String *conv = Getattr(pj, "implicitconv"); +	    if (conv && !implicitconvtypecheckoff) { +	      Replaceall(tm, "$implicitconv", conv); +	    } else { +	      Replaceall(tm, "$implicitconv", "0"); +	    } +	    Replaceall(tm, "$input", tmp); +	    Printv(f, "{\n", tm, "}\n", NIL); +	    Delete(tm); +	    fn = i + 1; +	    Printf(f, "if (!_v) goto check_%d;\n", fn); +	    Printf(f, "_ranki += _v*_pi;\n"); +	    Printf(f, "_rankm += _pi;\n"); +	    Printf(f, "_pi *= SWIG_MAXCASTRANK;\n"); +	  } +	} +	if (!Getattr(pj, "tmap:in:SWIGTYPE") && Getattr(pj, "tmap:typecheck:SWIGTYPE")) { +	  /* we emit  a warning if the argument defines the 'in' typemap, but not the 'typecheck' one */ +	  Swig_warning(WARN_TYPEMAP_TYPECHECK_UNDEF, Getfile(ni), Getline(ni), +		       "Overloaded method %s with no explicit typecheck typemap for arg %d of type '%s'\n", +		       Swig_name_decl(n), j, SwigType_str(Getattr(pj, "type"), 0)); +	} +	Parm *pj1 = Getattr(pj, "tmap:in:next"); +	if (pj1) +	  pj = pj1; +	else +	  pj = nextSibling(pj); +	j++; +      } +    } + +    /* close braces */ +    for ( /* empty */ ; num_braces > 0; num_braces--) +      Printf(f, "}\n"); + +    Printf(f, "if (!_index || (_ranki < _rank)) {\n"); +    Printf(f, " _rank = _ranki; _index = %d;\n", i + 1); +    Printf(f, " if (_rank == _rankm) goto dispatch;\n"); +    Printf(f, "}\n"); +    String *lfmt = ReplaceFormat(fmt, num_arguments); +    Printf(sw, "case %d:\n", i + 1); +    Printf(sw, Char(lfmt), Getattr(ni, "wrap:name")); +    Printf(sw, "\n"); + +    Printf(f, "}\n");		/* braces closes "if" for this method */ +    if (fn) +      Printf(f, "check_%d:\n\n", fn); + +    if (implicitconvtypecheckoff) +      Delattr(ni, "implicitconvtypecheckoff"); + +    Delete(lfmt); +    Delete(coll); +  } +  Delete(dispatch); +  Printf(f, "dispatch:\n"); +  Printf(f, "switch(_index) {\n"); +  Printf(f, "%s", sw); +  Printf(f, "}\n"); + +  Printf(f, "}\n"); +  return f; +} + +/* +  Fast dispatch mechanism, provided by  Salvador Fandi~no Garc'ia (#930586). +*/ +static String *overload_dispatch_fast(Node *n, const_String_or_char_ptr fmt, int *maxargs, const_String_or_char_ptr fmt_fastdispatch) { +  int i, j; + +  *maxargs = 1; + +  String *f = NewString(""); + +  /* Get a list of methods ranked by precedence values and argument count */ +  List *dispatch = Swig_overload_rank(n, true); +  int nfunc = Len(dispatch); + +  /* Loop over the functions */ + +  for (i = 0; i < nfunc; i++) { +    int fn = 0; +    Node *ni = Getitem(dispatch, i); +    Parm *pi = Getattr(ni, "wrap:parms"); +    bool implicitconvtypecheckoff = GetFlag(ni, "implicitconvtypecheckoff") != 0; +    int num_required = emit_num_required(pi); +    int num_arguments = emit_num_arguments(pi); +    if (num_arguments > *maxargs) +      *maxargs = num_arguments; + +    if (num_required == num_arguments) { +      Printf(f, "if (%s == %d) {\n", argc_template_string, num_required); +    } else { +      Printf(f, "if ((%s >= %d) && (%s <= %d)) {\n", argc_template_string, num_required, argc_template_string, num_arguments); +    } + +    /* create a list with the wrappers that collide with the +       current one based on argument number */ +    List *coll = NewList(); +    for (int k = i + 1; k < nfunc; k++) { +      Node *nk = Getitem(dispatch, k); +      Parm *pk = Getattr(nk, "wrap:parms"); +      int nrk = emit_num_required(pk); +      int nak = emit_num_arguments(pk); +      if ((nrk >= num_required && nrk <= num_arguments) || (nak >= num_required && nak <= num_arguments) || (nrk <= num_required && nak >= num_arguments)) +	Append(coll, nk); +    } + +    // printf("overload: %s coll=%d\n", Char(Getattr(n, "sym:name")), Len(coll)); + +    bool emitcheck = false; +    int num_braces = 0; +    bool test = (Len(coll) > 0 && num_arguments); +    if (test) { +      int need_v = 1; +      j = 0; +      Parm *pj = pi; +      while (pj) { +	if (checkAttribute(pj, "tmap:in:numinputs", "0")) { +	  pj = Getattr(pj, "tmap:in:next"); +	  continue; +	} + +	String *tm = Getattr(pj, "tmap:typecheck"); +	if (tm) { +	  tm = Copy(tm); +	  /* normalise for comparison later */ +	  Replaceid(tm, Getattr(pj, "lname"), "_v"); + +	  /* if all the wrappers have the same type check on this +	     argument we can optimize it out */ +	  emitcheck = false; +	  for (int k = 0; k < Len(coll) && !emitcheck; k++) { +	    Node *nk = Getitem(coll, k); +	    Parm *pk = Getattr(nk, "wrap:parms"); +	    int nak = emit_num_arguments(pk); +	    if (nak <= j) +	      continue; +	    int l = 0; +	    Parm *pl = pk; +	    /* finds arg j on the collider wrapper */ +	    while (pl && l <= j) { +	      if (checkAttribute(pl, "tmap:in:numinputs", "0")) { +		pl = Getattr(pl, "tmap:in:next"); +		continue; +	      } +	      if (l == j) { +		/* we are at arg j, so we compare the tmaps now */ +		String *tml = Getattr(pl, "tmap:typecheck"); +		/* normalise it before comparing */ +		if (tml) +		  Replaceid(tml, Getattr(pl, "lname"), "_v"); +		if (!tml || Cmp(tm, tml)) +		  emitcheck = true; +		//printf("tmap: %s[%d] (%d) => %s\n\n", +		//       Char(Getattr(nk, "sym:name")), +		//       l, emitcheck, tml?Char(tml):0); +	      } +	      Parm *pl1 = Getattr(pl, "tmap:in:next"); +	      if (pl1) +		pl = pl1; +	      else +		pl = nextSibling(pl); +	      l++; +	    } +	  } + +	  if (emitcheck) { +	    if (need_v) { +	      Printf(f, "int _v = 0;\n"); +	      need_v = 0; +	    } +	    if (j >= num_required) { +	      Printf(f, "if (%s > %d) {\n", argc_template_string, j); +	      num_braces++; +	    } +	    String *tmp = NewStringf(argv_template_string, j); + +	    String *conv = Getattr(pj, "implicitconv"); +	    if (conv && !implicitconvtypecheckoff) { +	      Replaceall(tm, "$implicitconv", conv); +	    } else { +	      Replaceall(tm, "$implicitconv", "0"); +	    } +	    Replaceall(tm, "$input", tmp); +	    Printv(f, "{\n", tm, "}\n", NIL); +	    Delete(tm); +	    fn = i + 1; +	    Printf(f, "if (!_v) goto check_%d;\n", fn); +	  } +	} +	if (!Getattr(pj, "tmap:in:SWIGTYPE") && Getattr(pj, "tmap:typecheck:SWIGTYPE")) { +	  /* we emit  a warning if the argument defines the 'in' typemap, but not the 'typecheck' one */ +	  Swig_warning(WARN_TYPEMAP_TYPECHECK_UNDEF, Getfile(ni), Getline(ni), +		       "Overloaded method %s with no explicit typecheck typemap for arg %d of type '%s'\n", +		       Swig_name_decl(n), j, SwigType_str(Getattr(pj, "type"), 0)); +	} +	Parm *pj1 = Getattr(pj, "tmap:in:next"); +	if (pj1) +	  pj = pj1; +	else +	  pj = nextSibling(pj); +	j++; +      } +    } + +    /* close braces */ +    for ( /* empty */ ; num_braces > 0; num_braces--) +      Printf(f, "}\n"); + +    // The language module may want to generate different code for last overloaded function called (with same number of arguments) +    String *lfmt = ReplaceFormat(!emitcheck && fmt_fastdispatch ? fmt_fastdispatch : fmt, num_arguments); +    Printf(f, Char(lfmt), Getattr(ni, "wrap:name")); + +    Printf(f, "}\n");		/* braces closes "if" for this method */ +    if (fn) +      Printf(f, "check_%d:\n\n", fn); + +    if (implicitconvtypecheckoff) +      Delattr(ni, "implicitconvtypecheckoff"); + +    Delete(lfmt); +    Delete(coll); +  } +  Delete(dispatch); +  return f; +} + +String *Swig_overload_dispatch(Node *n, const_String_or_char_ptr fmt, int *maxargs, const_String_or_char_ptr fmt_fastdispatch) { + +  if (fast_dispatch_mode || GetFlag(n, "feature:fastdispatch")) { +    return overload_dispatch_fast(n, fmt, maxargs, fmt_fastdispatch); +  } + +  int i, j; + +  *maxargs = 1; + +  String *f = NewString(""); + +  /* Get a list of methods ranked by precedence values and argument count */ +  List *dispatch = Swig_overload_rank(n, true); +  int nfunc = Len(dispatch); + +  /* Loop over the functions */ + +  for (i = 0; i < nfunc; i++) { +    Node *ni = Getitem(dispatch, i); +    Parm *pi = Getattr(ni, "wrap:parms"); +    bool implicitconvtypecheckoff = GetFlag(ni, "implicitconvtypecheckoff") != 0; +    int num_required = emit_num_required(pi); +    int num_arguments = emit_num_arguments(pi); +    if (GetFlag(n, "wrap:this")) { +      num_required++; +      num_arguments++; +    } +    if (num_arguments > *maxargs) +      *maxargs = num_arguments; + +    if (num_required == num_arguments) { +      Printf(f, "if (%s == %d) {\n", argc_template_string, num_required); +    } else { +      Printf(f, "if ((%s >= %d) && (%s <= %d)) {\n", argc_template_string, num_required, argc_template_string, num_arguments); +    } + +    if (num_arguments) { +      Printf(f, "int _v = 0;\n"); +    } + +    int num_braces = 0; +    j = 0; +    Parm *pj = pi; +    while (pj) { +      if (checkAttribute(pj, "tmap:in:numinputs", "0")) { +	pj = Getattr(pj, "tmap:in:next"); +	continue; +      } +      if (j >= num_required) { +	String *lfmt = ReplaceFormat(fmt, num_arguments); +	Printf(f, "if (%s <= %d) {\n", argc_template_string, j); +	Printf(f, Char(lfmt), Getattr(ni, "wrap:name")); +	Printf(f, "}\n"); +	Delete(lfmt); +      } +      if (print_typecheck(f, (GetFlag(n, "wrap:this") ? j + 1 : j), pj, implicitconvtypecheckoff)) { +	Printf(f, "if (_v) {\n"); +	num_braces++; +      } +      if (!Getattr(pj, "tmap:in:SWIGTYPE") && Getattr(pj, "tmap:typecheck:SWIGTYPE")) { +	/* we emit  a warning if the argument defines the 'in' typemap, but not the 'typecheck' one */ +	Swig_warning(WARN_TYPEMAP_TYPECHECK_UNDEF, Getfile(ni), Getline(ni), +		     "Overloaded method %s with no explicit typecheck typemap for arg %d of type '%s'\n", +		     Swig_name_decl(n), j, SwigType_str(Getattr(pj, "type"), 0)); +      } +      Parm *pk = Getattr(pj, "tmap:in:next"); +      if (pk) +	pj = pk; +      else +	pj = nextSibling(pj); +      j++; +    } +    String *lfmt = ReplaceFormat(fmt, num_arguments); +    Printf(f, Char(lfmt), Getattr(ni, "wrap:name")); +    Delete(lfmt); +    /* close braces */ +    for ( /* empty */ ; num_braces > 0; num_braces--) +      Printf(f, "}\n"); +    Printf(f, "}\n");		/* braces closes "if" for this method */ +    if (implicitconvtypecheckoff) +      Delattr(ni, "implicitconvtypecheckoff"); +  } +  Delete(dispatch); +  return f; +} + +/* ----------------------------------------------------------------------------- + * Swig_overload_check() + * ----------------------------------------------------------------------------- */ +void Swig_overload_check(Node *n) { +  Swig_overload_rank(n, false); +} diff --git a/contrib/tools/swig/Source/Modules/perl5.cxx b/contrib/tools/swig/Source/Modules/perl5.cxx new file mode 100644 index 00000000000..0cbf6b17a74 --- /dev/null +++ b/contrib/tools/swig/Source/Modules/perl5.cxx @@ -0,0 +1,2502 @@ +/* ---------------------------------------------------------------------------- + * This file is part of SWIG, which is licensed as a whole under version 3  + * (or any later version) of the GNU General Public License. Some additional + * terms also apply to certain portions of SWIG. The full details of the SWIG + * license and copyrights can be found in the LICENSE and COPYRIGHT files + * included with the SWIG source code as distributed by the SWIG developers + * and at https://www.swig.org/legal.html. + * + * perl5.cxx + * + * Perl5 language module for SWIG. + * ------------------------------------------------------------------------- */ + +#include "swigmod.h" +#include "cparse.h" +#include <ctype.h> + +static const char *usage = "\ +Perl 5 Options (available with -perl5)\n\ +     -compat         - Compatibility mode\n\ +     -const          - Wrap constants as constants and not variables (implies -proxy)\n\ +     -nopm           - Do not generate the .pm file\n\ +     -noproxy        - Don't create proxy classes\n\ +     -proxy          - Create proxy classes (enabled by default)\n\ +     -static         - Omit code related to dynamic loading\n\ +\n"; + +static int compat = 0; + +static int no_pmfile = 0; + +static int export_all = 0; + +/* + * pmfile + *   set by the -pm flag, overrides the name of the .pm file + */ +static String *pmfile = 0; + +/* + * module + *   set by the %module directive, e.g. "Xerces". It will determine + *   the name of the .pm file, and the dynamic library, and the name + *   used by any module wanting to %import the module. + */ +static String *module = 0; + +/* + * namespace_module + *   the fully namespace qualified name of the module. It will be used + *   to set the package namespace in the .pm file, as well as the name + *   of the initialization methods in the glue library. This will be + *   the same as module, above, unless the %module directive is given + *   the 'package' option, e.g. %module(package="Foo::Bar") "baz" + */ +static String       *namespace_module = 0; + +/* + * cmodule + *   the namespace of the internal glue code, set to the value of + *   module with a 'c' appended + */ +static String *cmodule = 0; + +/* + * dest_package + *   an optional namespace to put all classes into. Specified by using + *   the %module(package="Foo::Bar") "baz" syntax + */ +static String       *dest_package = 0; + +static String *command_tab = 0; +static String *constant_tab = 0; +static String *variable_tab = 0; + +static File *f_begin = 0; +static File *f_runtime = 0; +static File *f_runtime_h = 0; +static File *f_header = 0; +static File *f_wrappers = 0; +static File *f_directors = 0; +static File *f_directors_h = 0; +static File *f_init = 0; +static File *f_pm = 0; +static String *pm;		/* Package initialization code */ +static String *magic;		/* Magic variable wrappers     */ + +static int staticoption = 0; + +// controlling verbose output +static int          verbose = 0; + +/* The following variables are used to manage Perl5 classes */ + +static int blessed = 1;		/* Enable object oriented features */ +static int do_constants = 0;	/* Constant wrapping */ +static List *classlist = 0;	/* List of classes */ +static int have_constructor = 0; +static int have_destructor = 0; +static int have_data_members = 0; +static String *class_name = 0;	/* Name of the class (what Perl thinks it is) */ +static String *real_classname = 0;	/* Real name of C/C++ class */ +static String *fullclassname = 0; + +static String *pcode = 0;	/* Perl code associated with each class */ +						  /* static  String   *blessedmembers = 0;     *//* Member data associated with each class */ +static int member_func = 0;	/* Set to 1 when wrapping a member function */ +static String *func_stubs = 0;	/* Function stubs */ +static String *const_stubs = 0;	/* Constant stubs */ +static int num_consts = 0;	/* Number of constants */ +static String *var_stubs = 0;	/* Variable stubs */ +static String *exported = 0;	/* Exported symbols */ +static String *pragma_include = 0; +static String *additional_perl_code = 0;	/* Additional Perl code from %perlcode %{ ... %} */ +static Hash *operators = 0; +static int have_operators = 0; + +class PERL5:public Language { +public: + +  PERL5():Language () { +    Clear(argc_template_string); +    Printv(argc_template_string, "items", NIL); +    Clear(argv_template_string); +    Printv(argv_template_string, "ST(%d)", NIL); +    director_language = 1; +  } + +  /* Test to see if a type corresponds to something wrapped with a shadow class */ +  Node *is_shadow(SwigType *t) { +    Node *n; +    n = classLookup(t); +    /*  Printf(stdout,"'%s' --> '%p'\n", t, n); */ +    if (n) { +      if (!Getattr(n, "perl5:proxy")) { +	setclassname(n); +      } +      return Getattr(n, "perl5:proxy"); +    } +    return 0; +  } + +  /* ------------------------------------------------------------ +   * main() +   * ------------------------------------------------------------ */ + +  virtual void main(int argc, char *argv[]) { +    int i = 1; + +    SWIG_library_directory("perl5"); + +    for (i = 1; i < argc; i++) { +      if (argv[i]) { +	if (strcmp(argv[i], "-package") == 0) { +	  Printv(stderr, +		 "*** -package is no longer supported\n*** use the directive '%module A::B::C' in your interface file instead\n*** see the Perl section in the manual for details.\n", NIL); +	  Exit(EXIT_FAILURE); +	} else if (strcmp(argv[i], "-interface") == 0) { +	  Printv(stderr, +		 "*** -interface is no longer supported\n*** use the directive '%module A::B::C' in your interface file instead\n*** see the Perl section in the manual for details.\n", NIL); +	  Exit(EXIT_FAILURE); +	} else if (strcmp(argv[i], "-exportall") == 0) { +	  export_all = 1; +	  Swig_mark_arg(i); +	} else if (strcmp(argv[i], "-static") == 0) { +	  staticoption = 1; +	  Swig_mark_arg(i); +	} else if ((strcmp(argv[i], "-shadow") == 0) || ((strcmp(argv[i], "-proxy") == 0))) { +	  blessed = 1; +	  Swig_mark_arg(i); +	} else if ((strcmp(argv[i], "-noproxy") == 0)) { +	  blessed = 0; +	  Swig_mark_arg(i); +	} else if (strcmp(argv[i], "-const") == 0) { +	  do_constants = 1; +	  blessed = 1; +	  Swig_mark_arg(i); +	} else if (strcmp(argv[i], "-nopm") == 0) { +	  no_pmfile = 1; +	  Swig_mark_arg(i); +	} else if (strcmp(argv[i], "-pm") == 0) { +	  Swig_mark_arg(i); +	  i++; +	  pmfile = NewString(argv[i]); +	  Swig_mark_arg(i); +	} else if (strcmp(argv[i],"-v") == 0) { +	    Swig_mark_arg(i); +	    verbose++; +	} else if (strcmp(argv[i], "-compat") == 0) { +	  compat = 1; +	  Swig_mark_arg(i); +	} else if (strcmp(argv[i], "-help") == 0) { +	  fputs(usage, stdout); +	} else if (strcmp(argv[i], "-cppcast") == 0) { +	  Printf(stderr, "Deprecated command line option: %s. This option is now always on.\n", argv[i]); +	  Swig_mark_arg(i); +	} else if (strcmp(argv[i], "-nocppcast") == 0) { +	  Printf(stderr, "Deprecated command line option: %s. This option is no longer supported.\n", argv[i]); +	  Swig_mark_arg(i); +	  Exit(EXIT_FAILURE); +	} +      } +    } + +    Preprocessor_define("SWIGPERL 1", 0); +    // SWIGPERL5 is deprecated, and no longer documented. +    Preprocessor_define("SWIGPERL5 1", 0); +    SWIG_typemap_lang("perl5"); +    SWIG_config_file("perl5.swg"); +    allow_overloading(); +  } + +  /* ------------------------------------------------------------ +   * top() +   * ------------------------------------------------------------ */ + +  virtual int top(Node *n) { +    /* check if directors are enabled for this module.  note: this  +     * is a "master" switch, without which no director code will be +     * emitted.  %feature("director") statements are also required +     * to enable directors for individual classes or methods. +     * +     * use %module(directors="1") modulename at the start of the  +     * interface file to enable director generation. +     * +     * TODO: directors are disallowed in conjunction with many command +     * line options.  Some of them are probably safe, but it will take  +     * some effort to validate each one. +     */ +    { +      Node *mod = Getattr(n, "module"); +      if (mod) { +	Node *options = Getattr(mod, "options"); +	if (options) { +	  int dirprot = 0; +	  if (Getattr(options, "dirprot")) +	    dirprot = 1; +	  if (Getattr(options, "nodirprot")) +	    dirprot = 0; +	  if (Getattr(options, "directors")) { +	    int allow = 1; +	    if (export_all) { +	      Printv(stderr, "*** directors are not supported with -exportall\n", NIL); +	      allow = 0; +	    } +	    if (staticoption) { +	      Printv(stderr, "*** directors are not supported with -static\n", NIL); +	      allow = 0; +	    } +	    if (!blessed) { +	      Printv(stderr, "*** directors are not supported with -noproxy\n", NIL); +	      allow = 0; +	    } +	    if (no_pmfile) { +	      Printv(stderr, "*** directors are not supported with -nopm\n", NIL); +	      allow = 0; +	    } +	    if (compat) { +	      Printv(stderr, "*** directors are not supported with -compat\n", NIL); +	      allow = 0; +	    } +	    if (allow) { +	      allow_directors(); +	      if (dirprot) +		allow_dirprot(); +	    } +	  } +	} +      } +    } + +    /* Initialize all of the output files */ +    String *outfile = Getattr(n, "outfile"); +    String *outfile_h = Getattr(n, "outfile_h"); + +    f_begin = NewFile(outfile, "w", SWIG_output_files()); +    if (!f_begin) { +      FileErrorDisplay(outfile); +      Exit(EXIT_FAILURE); +    } +    f_runtime = NewString(""); +    f_init = NewString(""); +    f_header = NewString(""); +    f_wrappers = NewString(""); +    f_directors_h = NewString(""); +    f_directors = NewString(""); + +    if (directorsEnabled()) { +      f_runtime_h = NewFile(outfile_h, "w", SWIG_output_files()); +      if (!f_runtime_h) { +	FileErrorDisplay(outfile_h); +	Exit(EXIT_FAILURE); +      } +    } + +    /* Register file targets with the SWIG file handler */ +    Swig_register_filebyname("header", f_header); +    Swig_register_filebyname("wrapper", f_wrappers); +    Swig_register_filebyname("begin", f_begin); +    Swig_register_filebyname("runtime", f_runtime); +    Swig_register_filebyname("init", f_init); +    Swig_register_filebyname("director", f_directors); +    Swig_register_filebyname("director_h", f_directors_h); + +    classlist = NewList(); + +    pm = NewString(""); +    func_stubs = NewString(""); +    var_stubs = NewString(""); +    const_stubs = NewString(""); +    exported = NewString(""); +    magic = NewString(""); +    pragma_include = NewString(""); +    additional_perl_code = NewString(""); + +    command_tab = NewString("static swig_command_info swig_commands[] = {\n"); +    constant_tab = NewString("static swig_constant_info swig_constants[] = {\n"); +    variable_tab = NewString("static swig_variable_info swig_variables[] = {\n"); + +    Swig_banner(f_begin); + +    Swig_obligatory_macros(f_runtime, "PERL"); + +    if (directorsEnabled()) { +      Printf(f_runtime, "#define SWIG_DIRECTORS\n"); +    } +    Printf(f_runtime, "#define SWIG_CASTRANK_MODE\n"); +    Printf(f_runtime, "\n"); + +    // Is the imported module in another package?  (IOW, does it use the +    // %module(package="name") option and it's different than the package +    // of this module.) +    Node *mod = Getattr(n, "module"); +    Node *options = Getattr(mod, "options"); +    module = Copy(Getattr(n,"name")); + +    String *underscore_module = Copy(module); +    Replaceall(underscore_module,":","_"); + +    if (verbose > 0) { +      fprintf(stdout, "top: using namespace_module: %s\n", Char(namespace_module)); +    } + +    if (directorsEnabled()) { +      Swig_banner(f_directors_h); +      Printf(f_directors_h, "\n"); +      Printf(f_directors_h, "#ifndef SWIG_%s_WRAP_H_\n", underscore_module); +      Printf(f_directors_h, "#define SWIG_%s_WRAP_H_\n\n", underscore_module); +      if (dirprot_mode()) { +	Printf(f_directors_h, "#include <map>\n"); +	Printf(f_directors_h, "#include <string>\n\n"); +      } + +      Printf(f_directors, "\n\n"); +      Printf(f_directors, "/* ---------------------------------------------------\n"); +      Printf(f_directors, " * C++ director class methods\n"); +      Printf(f_directors, " * --------------------------------------------------- */\n\n"); +      if (outfile_h) { +	String *filename = Swig_file_filename(outfile_h); +	Printf(magic, "#include \"%s\"\n\n", filename); +	Delete(filename); +      } +    } + +    if (verbose > 0) { +      fprintf(stdout, "top: using module: %s\n", Char(module)); +    } + +    dest_package = options ? Getattr(options, "package") : 0; +    if (dest_package) { +      namespace_module = Copy(dest_package); +      if (verbose > 0) { +	fprintf(stdout, "top: Found package: %s\n",Char(dest_package)); +      } +    } else { +      namespace_module = Copy(module); +      if (verbose > 0) { +	fprintf(stdout, "top: No package found\n"); +      } +    } +    /* If we're in blessed mode, change the package name to "packagec" */ + +    if (blessed) { +      cmodule = NewStringf("%sc",namespace_module); +    } else { +      cmodule = NewString(namespace_module); +    } + +    /* Create a .pm file +     * Need to strip off any prefixes that might be found in +     * the module name */ + +    if (no_pmfile) { +      f_pm = NewString(0); +    } else { +      if (!pmfile) { +	char *m = Char(module) + Len(module); +	while (m != Char(module)) { +	  if (*m == ':') { +	    m++; +	    break; +	  } +	  m--; +	} +	pmfile = NewStringf("%s.pm", m); +      } +      String *filen = NewStringf("%s%s", SWIG_output_directory(), pmfile); +      if ((f_pm = NewFile(filen, "w", SWIG_output_files())) == 0) { +	FileErrorDisplay(filen); +	Exit(EXIT_FAILURE); +      } +      Delete(filen); +      filen = NULL; +      Swig_register_filebyname("pm", f_pm); +      Swig_register_filebyname("perl", f_pm); +    } +    { +      String *boot_name = NewStringf("boot_%s", underscore_module); +      Printf(f_header,"#define SWIG_init    %s\n\n", boot_name); +      Printf(f_header,"#define SWIG_name   \"%s::%s\"\n", cmodule, boot_name); +      Printf(f_header,"#define SWIG_prefix \"%s::\"\n", cmodule); +      Delete(boot_name); +    } + +    Swig_banner_target_lang(f_pm, "#"); +    Printf(f_pm, "\n"); + +    Printf(f_pm, "package %s;\n", module); + +    /*  +     * If the package option has been given we are placing our +     *   symbols into some other packages namespace, so we do not +     *   mess with @ISA or require for that package +     */ +    if (dest_package) { +      Printf(f_pm,"use base qw(DynaLoader);\n"); +    } else { +      Printf(f_pm,"use base qw(Exporter);\n"); +      if (!staticoption) { +	Printf(f_pm,"use base qw(DynaLoader);\n"); +      } +    } + +    /* Start creating magic code */ + +    Printv(magic, +           "#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n", +	   "#define MAGIC_CLASS\n", +	   "SWIGCLASS_STATIC int swig_magic_readonly(pTHX_ SV *SWIGUNUSEDPARM(sv), MAGIC *SWIGUNUSEDPARM(mg)) {\n", +	   tab4, "MAGIC_PPERL\n", tab4, "croak(\"Value is read-only.\");\n", tab4, "return 0;\n", "}\n", NIL); + +    Printf(f_wrappers, "#ifdef __cplusplus\nextern \"C\" {\n#endif\n"); + +    /* emit wrappers */ +    Language::top(n); + +    if (directorsEnabled()) { +      // Insert director runtime into the f_runtime file (make it occur before %header section) +      Swig_insert_file("director_common.swg", f_runtime); +      Swig_insert_file("director.swg", f_runtime); +    } + +    String *base = NewString(""); + +    /* Dump out variable wrappers */ + +    Printv(magic, "\n#ifdef __cplusplus\n}\n#endif\n", NIL); + +    Printf(f_header, "%s\n", magic); + +    String *type_table = NewString(""); + +    /* Patch the type table to reflect the names used by shadow classes */ +    if (blessed) { +      Iterator cls; +      for (cls = First(classlist); cls.item; cls = Next(cls)) { +	String *pname = Getattr(cls.item, "perl5:proxy"); +	if (pname) { +	  SwigType *type = Getattr(cls.item, "classtypeobj"); +	  if (!type) +	    continue;		/* If unnamed class, no type will be found */ +	  type = Copy(type); + +	  SwigType_add_pointer(type); +	  String *mangled = SwigType_manglestr(type); +	  SwigType_remember_mangleddata(mangled, NewStringf("\"%s\"", pname)); +	  Delete(type); +	  Delete(mangled); +	} +      } +    } +    SwigType_emit_type_table(f_runtime, type_table); + +    Printf(f_wrappers, "%s", type_table); +    Delete(type_table); + +    Printf(constant_tab, "{0,0,0,0,0,0}\n};\n"); +    Printv(f_wrappers, constant_tab, NIL); + +    Printf(f_wrappers, "#ifdef __cplusplus\n}\n#endif\n"); + +    Printf(f_init, "\t ST(0) = &PL_sv_yes;\n"); +    Printf(f_init, "\t XSRETURN(1);\n"); +    Printf(f_init, "}\n"); + +    /* Finish off tables */ +    Printf(variable_tab, "{0,0,0,0}\n};\n"); +    Printv(f_wrappers, variable_tab, NIL); + +    Printf(command_tab, "{0,0}\n};\n"); +    Printv(f_wrappers, command_tab, NIL); + + +    Printf(f_pm, "package %s;\n", cmodule); + +    if (!staticoption) { +      Printf(f_pm,"bootstrap %s;\n", module); +    } else { +      Printf(f_pm,"package %s;\n", cmodule); +      Printf(f_pm,"boot_%s();\n", underscore_module); +    } + +    Printf(f_pm, "package %s;\n", module); +    /*  +     * If the package option has been given we are placing our +     *   symbols into some other packages namespace, so we do not +     *   mess with @EXPORT +     */ +    if (!dest_package) { +      Printf(f_pm,"@EXPORT = qw(%s);\n", exported); +    } + +    Printf(f_pm, "%s", pragma_include); + +    if (blessed) { + +      /* +       * These methods will be duplicated if package  +       *   has been specified, so we do not output them +       */ +      if (!dest_package) { +	Printv(base, "\n# ---------- BASE METHODS -------------\n\n", "package ", namespace_module, ";\n\n", NIL); + +	/* Write out the TIE method */ + +	Printv(base, "sub TIEHASH {\n", tab4, "my ($classname,$obj) = @_;\n", tab4, "return bless $obj, $classname;\n", "}\n\n", NIL); + +	/* Output a CLEAR method.   This is just a place-holder, but by providing it we +	 * can make declarations such as +	 *     %$u = ( x => 2, y=>3, z =>4 ); +	 * +	 * Where x,y,z are the members of some C/C++ object. */ + +	Printf(base, "sub CLEAR { }\n\n"); + +	/* Output default firstkey/nextkey methods */ + +	Printf(base, "sub FIRSTKEY { }\n\n"); +	Printf(base, "sub NEXTKEY { }\n\n"); + +	/* Output a FETCH method.  This is actually common to all classes */ +	Printv(base, +	       "sub FETCH {\n", +	       tab4, "my ($self,$field) = @_;\n", tab4, "my $member_func = \"swig_${field}_get\";\n", tab4, "$self->$member_func();\n", "}\n\n", NIL); + +	/* Output a STORE method.   This is also common to all classes (might move to base class) */ + +	Printv(base, +	       "sub STORE {\n", +	       tab4, "my ($self,$field,$newval) = @_;\n", +	       tab4, "my $member_func = \"swig_${field}_set\";\n", tab4, "$self->$member_func($newval);\n", "}\n\n", NIL); + +	/* Output a 'this' method */ + +	Printv(base, "sub this {\n", tab4, "my $ptr = shift;\n", tab4, "return tied(%$ptr);\n", "}\n\n", NIL); + +	Printf(f_pm, "%s", base); +      } + +      /* Emit function stubs for stand-alone functions */ +      Printf(f_pm, "\n# ------- FUNCTION WRAPPERS --------\n\n"); +      Printf(f_pm, "package %s;\n\n", namespace_module); +      Printf(f_pm, "%s", func_stubs); + +      /* Emit package code for different classes */ +      Printf(f_pm, "%s", pm); + +      if (num_consts > 0) { +	/* Emit constant stubs */ +	Printf(f_pm, "\n# ------- CONSTANT STUBS -------\n\n"); +	Printf(f_pm, "package %s;\n\n", namespace_module); +	Printf(f_pm, "%s", const_stubs); +      } + +      /* Emit variable stubs */ + +      Printf(f_pm, "\n# ------- VARIABLE STUBS --------\n\n"); +      Printf(f_pm, "package %s;\n\n", namespace_module); +      Printf(f_pm, "%s", var_stubs); +    } + +    /* Add additional Perl code at the end */ +    Printf(f_pm, "%s", additional_perl_code); + +    Printf(f_pm, "1;\n"); +    Delete(f_pm); +    Delete(base); +    Delete(dest_package); +    Delete(underscore_module); + +    /* Close all of the files */ +    Dump(f_runtime, f_begin); +    Dump(f_header, f_begin); + +    if (directorsEnabled()) { +      Dump(f_directors_h, f_runtime_h); +      Printf(f_runtime_h, "\n"); +      Printf(f_runtime_h, "#endif\n"); +      Dump(f_directors, f_begin); +    } + +    Dump(f_wrappers, f_begin); +    Wrapper_pretty_print(f_init, f_begin); +    Delete(f_header); +    Delete(f_wrappers); +    Delete(f_init); +    Delete(f_directors); +    Delete(f_directors_h); +    Delete(f_runtime); +    Delete(f_begin); +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * importDirective(Node *n) +   * ------------------------------------------------------------ */ + +  virtual int importDirective(Node *n) { +    if (blessed) { +      String *modname = Getattr(n, "module"); +      if (modname) { +	Printf(f_pm, "require %s;\n", modname); +      } +    } +    return Language::importDirective(n); +  } + +  /* ------------------------------------------------------------ +   * functionWrapper() +   * ------------------------------------------------------------ */ + +  virtual int functionWrapper(Node *n) { +    String *name = Getattr(n, "name"); +    String *iname = Getattr(n, "sym:name"); +    SwigType *d = Getattr(n, "type"); +    ParmList *l = Getattr(n, "parms"); +    String *overname = 0; +    int director_method = 0; + +    Parm *p; +    int i; +    Wrapper *f; +    char source[256], temp[256]; +    String *tm; +    String *cleanup, *outarg; +    int num_saved = 0; +    int num_arguments, num_required; +    int varargs = 0; + +    if (Getattr(n, "sym:overloaded")) { +      overname = Getattr(n, "sym:overname"); +    } else { +      if (!addSymbol(iname, n)) +	return SWIG_ERROR; +    } + +    f = NewWrapper(); +    cleanup = NewString(""); +    outarg = NewString(""); + +    String *wname = Swig_name_wrapper(iname); +    if (overname) { +      Append(wname, overname); +    } +    Setattr(n, "wrap:name", wname); +    Printv(f->def, "XS(", wname, ") {\n", "{\n",	/* scope to destroy C++ objects before croaking */ +	   NIL); + +    emit_parameter_variables(l, f); +    emit_attach_parmmaps(l, f); +    Setattr(n, "wrap:parms", l); + +    num_arguments = emit_num_arguments(l); +    num_required = emit_num_required(l); +    varargs = emit_isvarargs(l); + +    Wrapper_add_local(f, "argvi", "int argvi = 0"); + +    /* Check the number of arguments */ +    if (!varargs) { +      Printf(f->code, "    if ((items < %d) || (items > %d)) {\n", num_required, num_arguments); +    } else { +      Printf(f->code, "    if (items < %d) {\n", num_required); +    } +    Printf(f->code, "        SWIG_croak(\"Usage: %s\");\n", usage_func(Char(iname), d, l)); +    Printf(f->code, "}\n"); + +    /* Write code to extract parameters. */ +    for (i = 0, p = l; i < num_arguments; i++) { + +      /* Skip ignored arguments */ + +      while (checkAttribute(p, "tmap:in:numinputs", "0")) { +	p = Getattr(p, "tmap:in:next"); +      } + +      SwigType *pt = Getattr(p, "type"); + +      /* Produce string representation of source and target arguments */ +      sprintf(source, "ST(%d)", i); + +      if (i >= num_required) { +	Printf(f->code, "    if (items > %d) {\n", i); +      } +      if ((tm = Getattr(p, "tmap:in"))) { +	Replaceall(tm, "$input", source); +	Setattr(p, "emit:input", source);	/* Save input location */ + +	if (Getattr(p, "wrap:disown") || (Getattr(p, "tmap:in:disown"))) { +	  Replaceall(tm, "$disown", "SWIG_POINTER_DISOWN"); +	} else { +	  Replaceall(tm, "$disown", "0"); +	} + +	Printf(f->code, "%s\n", tm); +	p = Getattr(p, "tmap:in:next"); +      } else { +	Swig_warning(WARN_TYPEMAP_IN_UNDEF, input_file, line_number, "Unable to use type %s as a function argument.\n", SwigType_str(pt, 0)); +	p = nextSibling(p); +      } +      if (i >= num_required) { +	Printf(f->code, "    }\n"); +      } +    } + +    if (varargs) { +      if (p && (tm = Getattr(p, "tmap:in"))) { +	sprintf(source, "ST(%d)", i); +	Replaceall(tm, "$input", source); +	Setattr(p, "emit:input", source); +	Printf(f->code, "if (items >= %d) {\n", i); +	Printv(f->code, tm, "\n", NIL); +	Printf(f->code, "}\n"); +      } +    } + +    /* Insert constraint checking code */ +    for (p = l; p;) { +      if ((tm = Getattr(p, "tmap:check"))) { +	Printv(f->code, tm, "\n", NIL); +	p = Getattr(p, "tmap:check:next"); +      } else { +	p = nextSibling(p); +      } +    } + +    /* Insert cleanup code */ +    for (i = 0, p = l; p; i++) { +      if ((tm = Getattr(p, "tmap:freearg"))) { +	Replaceall(tm, "$arg", Getattr(p, "emit:input")); +	Replaceall(tm, "$input", Getattr(p, "emit:input")); +	Printv(cleanup, tm, "\n", NIL); +	p = Getattr(p, "tmap:freearg:next"); +      } else { +	p = nextSibling(p); +      } +    } + +    /* Insert argument output code */ +    num_saved = 0; +    for (i = 0, p = l; p; i++) { +      if ((tm = Getattr(p, "tmap:argout"))) { +	SwigType *t = Getattr(p, "type"); +	Replaceall(tm, "$result", "ST(argvi)"); +	if (is_shadow(t)) { +	  Replaceall(tm, "$shadow", "SWIG_SHADOW"); +	} else { +	  Replaceall(tm, "$shadow", "0"); +	} + +	String *in = Getattr(p, "emit:input"); +	if (in) { +	  sprintf(temp, "_saved[%d]", num_saved); +	  Replaceall(tm, "$arg", temp); +	  Replaceall(tm, "$input", temp); +	  Printf(f->code, "_saved[%d] = %s;\n", num_saved, in); +	  num_saved++; +	} +	Printv(outarg, tm, "\n", NIL); +	p = Getattr(p, "tmap:argout:next"); +      } else { +	p = nextSibling(p); +      } +    } + +    /* If there were any saved arguments, emit a local variable for them */ +    if (num_saved) { +      sprintf(temp, "_saved[%d]", num_saved); +      Wrapper_add_localv(f, "_saved", "SV *", temp, NIL); +    } + +    director_method = is_member_director(n) && !is_smart_pointer() && 0 != Cmp(nodeType(n), "destructor"); +    if (director_method) { +      Wrapper_add_local(f, "director", "Swig::Director *director = 0"); +      Append(f->code, "director = SWIG_DIRECTOR_CAST(arg1);\n"); +      if (dirprot_mode() && !is_public(n)) { +	Printf(f->code, "if (!director || !(director->swig_get_inner(\"%s\"))) {\n", name); +	Printf(f->code, "SWIG_exception_fail(SWIG_RuntimeError, \"accessing protected member %s\");\n", name); +	Append(f->code, "}\n"); +      } +      Wrapper_add_local(f, "upcall", "bool upcall = false"); +      Printf(f->code, "upcall = director && SvSTASH(SvRV(ST(0))) == gv_stashpv(director->swig_get_class(), 0);\n"); +    } + +    /* Emit the function call */ +    if (director_method) { +      Append(f->code, "try {\n"); +    } + +    /* Now write code to make the function call */ + +    Swig_director_emit_dynamic_cast(n, f); +    String *actioncode = emit_action(n); + +    if (director_method) { +      Append(actioncode, "} catch (Swig::DirectorException& swig_err) {\n"); +      Append(actioncode, "  sv_setsv(ERRSV, swig_err.getNative());\n"); +      Append(actioncode, "  SWIG_fail;\n"); +      Append(actioncode, "}\n"); +    } + +    if ((tm = Swig_typemap_lookup_out("out", n, Swig_cresult_name(), f, actioncode))) { +      SwigType *t = Getattr(n, "type"); +      Replaceall(tm, "$result", "ST(argvi)"); +      if (is_shadow(t)) { +	Replaceall(tm, "$shadow", "SWIG_SHADOW"); +      } else { +	Replaceall(tm, "$shadow", "0"); +      } +      if (GetFlag(n, "feature:new")) { +	Replaceall(tm, "$owner", "SWIG_OWNER"); +      } else { +	Replaceall(tm, "$owner", "0"); +      } +      Printf(f->code, "%s\n", tm); +    } else { +      Swig_warning(WARN_TYPEMAP_OUT_UNDEF, input_file, line_number, "Unable to use return type %s in function %s.\n", SwigType_str(d, 0), name); +    } +    emit_return_variable(n, d, f); + +    /* If there were any output args, take care of them. */ + +    Printv(f->code, outarg, NIL); + +    /* If there was any cleanup, do that. */ + +    Printv(f->code, cleanup, NIL); + +    if (GetFlag(n, "feature:new")) { +      if ((tm = Swig_typemap_lookup("newfree", n, Swig_cresult_name(), 0))) { +	Printf(f->code, "%s\n", tm); +      } +    } + +    if ((tm = Swig_typemap_lookup("ret", n, Swig_cresult_name(), 0))) { +      Printf(f->code, "%s\n", tm); +    } + +    if (director_method) { +      if ((tm = Swig_typemap_lookup("directorfree", n, Swig_cresult_name(), 0))) { +	Replaceall(tm, "$input", Swig_cresult_name()); +	Replaceall(tm, "$result", "ST(argvi)"); +	Printf(f->code, "%s\n", tm); +	Delete(tm); +      } +    } + +    Printv(f->code, "XSRETURN(argvi);\n", "fail:\n", cleanup, "SWIG_croak_null();\n" "}\n" "}\n", NIL); + +    /* Add the dXSARGS last */ + +    Wrapper_add_local(f, "dXSARGS", "dXSARGS"); + +    /* Substitute the cleanup code */ +    Replaceall(f->code, "$cleanup", cleanup); +    Replaceall(f->code, "$symname", iname); + +    /* Dump the wrapper function */ + +    Wrapper_print(f, f_wrappers); + +    /* Now register the function */ + +    if (!Getattr(n, "sym:overloaded")) { +      Printf(command_tab, "{\"%s::%s\", %s},\n", cmodule, iname, wname); +    } else if (!Getattr(n, "sym:nextSibling")) { +      /* Generate overloaded dispatch function */ +      int maxargs; +      String *dispatch = Swig_overload_dispatch_cast(n, "PUSHMARK(MARK); SWIG_CALLXS(%s); return;", &maxargs); + +      /* Generate a dispatch wrapper for all overloaded functions */ + +      Wrapper *df = NewWrapper(); +      String *dname = Swig_name_wrapper(iname); + +      Printv(df->def, "XS(", dname, ") {\n", NIL); + +      Wrapper_add_local(df, "dXSARGS", "dXSARGS"); +      Printv(df->code, dispatch, "\n", NIL); +      Printf(df->code, "croak(\"No matching function for overloaded '%s'\");\n", iname); +      Printf(df->code, "XSRETURN(0);\n"); +      Printv(df->code, "}\n", NIL); +      Wrapper_print(df, f_wrappers); +      Printf(command_tab, "{\"%s::%s\", %s},\n", cmodule, iname, dname); +      DelWrapper(df); +      Delete(dispatch); +      Delete(dname); +    } +    if (!Getattr(n, "sym:nextSibling")) { +      if (export_all) { +	Printf(exported, "%s ", iname); +      } + +      /* -------------------------------------------------------------------- +       * Create a stub for this function, provided it's not a member function +       * -------------------------------------------------------------------- */ + +      if ((blessed) && (!member_func)) { +	Printv(func_stubs, "*", iname, " = *", cmodule, "::", iname, ";\n", NIL); +      } + +    } +    Delete(cleanup); +    Delete(outarg); +    DelWrapper(f); +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * variableWrapper() +   * ------------------------------------------------------------ */ +  virtual int variableWrapper(Node *n) { +    String *name = Getattr(n, "name"); +    String *iname = Getattr(n, "sym:name"); +    SwigType *t = Getattr(n, "type"); +    Wrapper *getf, *setf; +    String *tm; +    String *getname = Swig_name_get(NSPACE_TODO, iname); +    String *setname = Swig_name_set(NSPACE_TODO, iname); + +    String *get_name = Swig_name_wrapper(getname); +    String *set_name = Swig_name_wrapper(setname); + +    if (!addSymbol(iname, n)) +      return SWIG_ERROR; + +    getf = NewWrapper(); +    setf = NewWrapper(); + +    /* Create a Perl function for setting the variable value */ + +    if (!GetFlag(n, "feature:immutable")) { +      Setattr(n, "wrap:name", set_name); +      Printf(setf->def, "SWIGCLASS_STATIC int %s(pTHX_ SV* sv, MAGIC * SWIGUNUSEDPARM(mg)) {\n", set_name); +      Printv(setf->code, tab4, "MAGIC_PPERL\n", NIL); + +      /* Check for a few typemaps */ +      tm = Swig_typemap_lookup("varin", n, name, 0); +      if (tm) { +	Replaceall(tm, "$input", "sv"); +	/* Printf(setf->code,"%s\n", tm); */ +	emit_action_code(n, setf->code, tm); +      } else { +	Swig_warning(WARN_TYPEMAP_VARIN_UNDEF, input_file, line_number, "Unable to set variable of type %s.\n", SwigType_str(t, 0)); +	DelWrapper(setf); +	DelWrapper(getf); +	return SWIG_NOWRAP; +      } +      Printf(setf->code, "fail:\n"); +      Printf(setf->code, "    return 1;\n}\n"); +      Replaceall(setf->code, "$symname", iname); +      Wrapper_print(setf, magic); +    } + +    /* Now write a function to evaluate the variable */ +    Setattr(n, "wrap:name", get_name); +    int addfail = 0; +    Printf(getf->def, "SWIGCLASS_STATIC int %s(pTHX_ SV *sv, MAGIC *SWIGUNUSEDPARM(mg)) {\n", get_name); +    Printv(getf->code, tab4, "MAGIC_PPERL\n", NIL); + +    if ((tm = Swig_typemap_lookup("varout", n, name, 0))) { +      Replaceall(tm, "$result", "sv"); +      if (is_shadow(t)) { +	Replaceall(tm, "$shadow", "SWIG_SHADOW"); +      } else { +	Replaceall(tm, "$shadow", "0"); +      } +      /* Printf(getf->code,"%s\n", tm); */ +      addfail = emit_action_code(n, getf->code, tm); +    } else { +      Swig_warning(WARN_TYPEMAP_VAROUT_UNDEF, input_file, line_number, "Unable to read variable of type %s\n", SwigType_str(t, 0)); +      DelWrapper(setf); +      DelWrapper(getf); +      return SWIG_NOWRAP; +    } +    Printf(getf->code, "    return 1;\n"); +    if (addfail) { +      Append(getf->code, "fail:\n"); +      Append(getf->code, "  return 0;\n"); +    } +    Append(getf->code, "}\n"); + + +    Replaceall(getf->code, "$symname", iname); +    Wrapper_print(getf, magic); + +    String *tt = Getattr(n, "tmap:varout:type"); +    if (tt) { +      tt = NewStringf("&%s", tt); +    } else { +      tt = NewString("0"); +    } +    /* Now add symbol to the PERL interpreter */ +    if (GetFlag(n, "feature:immutable")) { +      Printv(variable_tab, tab4, "{ \"", cmodule, "::", iname, "\", MAGIC_CLASS swig_magic_readonly, MAGIC_CLASS ", get_name, ",", tt, " },\n", NIL); + +    } else { +      Printv(variable_tab, tab4, "{ \"", cmodule, "::", iname, "\", MAGIC_CLASS ", set_name, ", MAGIC_CLASS ", get_name, ",", tt, " },\n", NIL); +    } + +    /* If we're blessed, try to figure out what to do with the variable +       1.  If it's a Perl object of some sort, create a tied-hash +       around it. +       2.  Otherwise, just hack Perl's symbol table */ + +    if (blessed) { +      if (is_shadow(t)) { +	Printv(var_stubs, +	       "\nmy %__", iname, "_hash;\n", +	       "tie %__", iname, "_hash,\"", is_shadow(t), "\", $", +	       cmodule, "::", iname, ";\n", "$", iname, "= \\%__", iname, "_hash;\n", "bless $", iname, ", ", is_shadow(t), ";\n", NIL); +      } else { +	Printv(var_stubs, "*", iname, " = *", cmodule, "::", iname, ";\n", NIL); +      } +    } +    if (export_all) +      Printf(exported, "$%s ", iname); + +    Delete(tt); +    DelWrapper(setf); +    DelWrapper(getf); +    Delete(getname); +    Delete(setname); +    Delete(set_name); +    Delete(get_name); +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * constantWrapper() +   * ------------------------------------------------------------ */ + +  virtual int constantWrapper(Node *n) { +    String *name = Getattr(n, "name"); +    String *iname = Getattr(n, "sym:name"); +    SwigType *type = Getattr(n, "type"); +    String *rawval = Getattr(n, "rawval"); +    String *value = rawval ? rawval : Getattr(n, "value"); +    String *tm; + +    if (!addSymbol(iname, n)) +      return SWIG_ERROR; + +    /* Special hook for member pointer */ +    if (SwigType_type(type) == T_MPOINTER) { +      String *wname = Swig_name_wrapper(iname); +      Printf(f_wrappers, "static %s = %s;\n", SwigType_str(type, wname), value); +      value = Char(wname); +    } + +    if ((tm = Swig_typemap_lookup("consttab", n, name, 0))) { +      Replaceall(tm, "$value", value); +      if (is_shadow(type)) { +	Replaceall(tm, "$shadow", "SWIG_SHADOW"); +      } else { +	Replaceall(tm, "$shadow", "0"); +      } +      Printf(constant_tab, "%s,\n", tm); +    } else if ((tm = Swig_typemap_lookup("constcode", n, name, 0))) { +      Replaceall(tm, "$value", value); +      if (is_shadow(type)) { +	Replaceall(tm, "$shadow", "SWIG_SHADOW"); +      } else { +	Replaceall(tm, "$shadow", "0"); +      } +      Printf(f_init, "%s\n", tm); +    } else { +      Swig_warning(WARN_TYPEMAP_CONST_UNDEF, input_file, line_number, "Unsupported constant value.\n"); +      return SWIG_NOWRAP; +    } + +    if (blessed) { +      if (is_shadow(type)) { +	Printv(var_stubs, +	       "\nmy %__", iname, "_hash;\n", +	       "tie %__", iname, "_hash,\"", is_shadow(type), "\", $", +	       cmodule, "::", iname, ";\n", "$", iname, "= \\%__", iname, "_hash;\n", "bless $", iname, ", ", is_shadow(type), ";\n", NIL); +      } else if (do_constants) { +	Printv(const_stubs, "sub ", name, " () { $", cmodule, "::", name, " }\n", NIL); +	num_consts++; +      } else { +	Printv(var_stubs, "*", iname, " = *", cmodule, "::", iname, ";\n", NIL); +      } +    } +    if (export_all) { +      if (do_constants && !is_shadow(type)) { +	Printf(exported, "%s ", name); +      } else { +	Printf(exported, "$%s ", iname); +      } +    } +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * usage_func() +   * ------------------------------------------------------------ */ +  char *usage_func(char *iname, SwigType *, ParmList *l) { +    static String *temp = 0; +    Parm *p; +    int i; + +    if (!temp) +      temp = NewString(""); +    Clear(temp); +    Printf(temp, "%s(", iname); + +    /* Now go through and print parameters */ +    p = l; +    i = 0; +    while (p != 0) { +      SwigType *pt = Getattr(p, "type"); +      String *pn = Getattr(p, "name"); +      if (!checkAttribute(p,"tmap:in:numinputs","0")) { +	/* If parameter has been named, use that.   Otherwise, just print a type  */ +	if (SwigType_type(pt) != T_VOID) { +	  if (Len(pn) > 0) { +	    Printf(temp, "%s", pn); +	  } else { +	    Printf(temp, "%s", SwigType_str(pt, 0)); +	  } +	} +	i++; +	p = nextSibling(p); +	if (p) +	  if (!checkAttribute(p,"tmap:in:numinputs","0")) +	    Putc(',', temp); +      } else { +	p = nextSibling(p); +	if (p) +	  if ((i > 0) && (!checkAttribute(p,"tmap:in:numinputs","0"))) +	    Putc(',', temp); +      } +    } +    Printf(temp, ");"); +    return Char(temp); +  } + +  /* ------------------------------------------------------------ +   * nativeWrapper() +   * ------------------------------------------------------------ */ + +  virtual int nativeWrapper(Node *n) { +    String *name = Getattr(n, "sym:name"); +    String *funcname = Getattr(n, "wrap:name"); + +    if (!addSymbol(funcname, n)) +      return SWIG_ERROR; + +    Printf(command_tab, "{\"%s::%s\", %s},\n", cmodule, name, funcname); +    if (export_all) +      Printf(exported, "%s ", name); +    if (blessed) { +      Printv(func_stubs, "*", name, " = *", cmodule, "::", name, ";\n", NIL); +    } +    return SWIG_OK; +  } + +/* ---------------------------------------------------------------------------- + *                      OBJECT-ORIENTED FEATURES + * + * These extensions provide a more object-oriented interface to C++ + * classes and structures.    The code here is based on extensions + * provided by David Fletcher and Gary Holt. + * + * I have generalized these extensions to make them more general purpose + * and to resolve object-ownership problems. + * + * The approach here is very similar to the Python module : + *       1.   All of the original methods are placed into a single + *            package like before except that a 'c' is appended to the + *            package name. + * + *       2.   All methods and function calls are wrapped with a new + *            perl function.   While possibly inefficient this allows + *            us to catch complex function arguments (which are hard to + *            track otherwise). + * + *       3.   Classes are represented as tied-hashes in a manner similar + *            to Gary Holt's extension.   This allows us to access + *            member data. + * + *       4.   Stand-alone (global) C functions are modified to take + *            tied hashes as arguments for complex datatypes (if + *            appropriate). + * + *       5.   Global variables involving a class/struct is encapsulated + *            in a tied hash. + * + * ------------------------------------------------------------------------- */ + + +  void setclassname(Node *n) { +    String *symname = Getattr(n, "sym:name"); +    String *fullname; +    String *actualpackage; +    Node *clsmodule = Getattr(n, "module"); + +    if (!clsmodule) { +      /* imported module does not define a module name.   Oh well */ +      return; +    } + +    /* Do some work on the class name */ +    if (verbose > 0) { +      String *modulename = Getattr(clsmodule, "name"); +      fprintf(stdout, "setclassname: Found sym:name: %s\n", Char(symname)); +      fprintf(stdout, "setclassname: Found module: %s\n", Char(modulename)); +      fprintf(stdout, "setclassname: No package found\n"); +    } + +    if (dest_package) { +      fullname = NewStringf("%s::%s", namespace_module, symname); +    } else { +      actualpackage = Getattr(clsmodule,"name"); + +      if (verbose > 0) { +	fprintf(stdout, "setclassname: Found actualpackage: %s\n", Char(actualpackage)); +      } +      if ((!compat) && (!Strchr(symname,':'))) { +	fullname = NewStringf("%s::%s",actualpackage,symname); +      } else { +	fullname = NewString(symname); +      } +    } +    if (verbose > 0) { +      fprintf(stdout, "setclassname: setting proxy: %s\n", Char(fullname)); +    } +    Setattr(n, "perl5:proxy", fullname); +  } + +  /* ------------------------------------------------------------ +   * classDeclaration() +   * ------------------------------------------------------------ */ +  virtual int classDeclaration(Node *n) { +    /* Do some work on the class name */ +    if (!Getattr(n, "feature:onlychildren")) { +      if (blessed) { +	setclassname(n); +	Append(classlist, n); +      } +    } + +    return Language::classDeclaration(n); +  } + +  /* ------------------------------------------------------------ +   * classHandler() +   * ------------------------------------------------------------ */ + +  virtual int classHandler(Node *n) { + +    if (blessed) { +      have_constructor = 0; +      have_operators = 0; +      have_destructor = 0; +      have_data_members = 0; +      operators = NewHash(); + +      class_name = Getattr(n, "sym:name"); + +      if (!addSymbol(class_name, n)) +	return SWIG_ERROR; + +      /* Use the fully qualified name of the Perl class */ +      if (!compat) { +	fullclassname = NewStringf("%s::%s", namespace_module, class_name); +      } else { +	fullclassname = NewString(class_name); +      } +      real_classname = Getattr(n, "name"); +      pcode = NewString(""); +      // blessedmembers = NewString(""); +    } + +    /* Emit all of the members */ +    Language::classHandler(n); + + +    /* Finish the rest of the class */ +    if (blessed) { +      /* Generate a client-data entry */ +      SwigType *ct = NewStringf("p.%s", real_classname); +      Printv(f_init, "SWIG_TypeClientData(SWIGTYPE", SwigType_manglestr(ct), ", (void*) \"", fullclassname, "\");\n", NIL); +      SwigType_remember(ct); +      Delete(ct); + +      Printv(pm, "\n############# Class : ", fullclassname, " ##############\n", "\npackage ", fullclassname, ";\n", NIL); + +      if (have_operators) { +	Printf(pm, "use overload\n"); +	Iterator ki; +	for (ki = First(operators); ki.key; ki = Next(ki)) { +	  char *name = Char(ki.key); +	  //        fprintf(stderr,"found name: <%s>\n", name); +	  if (strstr(name, "__eq__")) { +	    Printv(pm, tab4, "\"==\" => sub { $_[0]->__eq__($_[1])},\n",NIL); +	  } else if (strstr(name, "__ne__")) { +	    Printv(pm, tab4, "\"!=\" => sub { $_[0]->__ne__($_[1])},\n",NIL); +	    // there are no tests for this in operator_overload_runme.pl +	    // it is likely to be broken +	    //	  } else if (strstr(name, "__assign__")) { +	    //	    Printv(pm, tab4, "\"=\" => sub { $_[0]->__assign__($_[1])},\n",NIL); +	  } else if (strstr(name, "__str__")) { +	    Printv(pm, tab4, "'\"\"' => sub { $_[0]->__str__()},\n",NIL); +	  } else if (strstr(name, "__plusplus__")) { +	    Printv(pm, tab4, "\"++\" => sub { $_[0]->__plusplus__()},\n",NIL); +	  } else if (strstr(name, "__minmin__")) { +	    Printv(pm, tab4, "\"--\" => sub { $_[0]->__minmin__()},\n",NIL); +	  } else if (strstr(name, "__add__")) { +	    Printv(pm, tab4, "\"+\" => sub { $_[0]->__add__($_[1])},\n",NIL); +	  } else if (strstr(name, "__sub__")) { +	    Printv(pm, tab4, "\"-\" => sub {  if( not $_[2] ) { $_[0]->__sub__($_[1]) }\n",NIL); +	    Printv(pm, tab8, "elsif( $_[0]->can('__rsub__') ) { $_[0]->__rsub__($_[1]) }\n",NIL); +	    Printv(pm, tab8, "else { die(\"reverse subtraction not supported\") }\n",NIL); +	    Printv(pm, tab8, "},\n",NIL); +	  } else if (strstr(name, "__mul__")) { +	    Printv(pm, tab4, "\"*\" => sub { $_[0]->__mul__($_[1])},\n",NIL); +	  } else if (strstr(name, "__div__")) { +	    Printv(pm, tab4, "\"/\" => sub { $_[0]->__div__($_[1])},\n",NIL); +	  } else if (strstr(name, "__mod__")) { +	    Printv(pm, tab4, "\"%\" => sub { $_[0]->__mod__($_[1])},\n",NIL); +	    // there are no tests for this in operator_overload_runme.pl +	    // it is likely to be broken +	    //	  } else if (strstr(name, "__and__")) { +	    //	    Printv(pm, tab4, "\"&\" => sub { $_[0]->__and__($_[1])},\n",NIL); + +	    // there are no tests for this in operator_overload_runme.pl +	    // it is likely to be broken +	    //	  } else if (strstr(name, "__or__")) { +	    //	    Printv(pm, tab4, "\"|\" => sub { $_[0]->__or__($_[1])},\n",NIL); +	  } else if (strstr(name, "__gt__")) { +	    Printv(pm, tab4, "\">\" => sub { $_[0]->__gt__($_[1])},\n",NIL); +          } else if (strstr(name, "__ge__")) { +            Printv(pm, tab4, "\">=\" => sub { $_[0]->__ge__($_[1])},\n",NIL); +	  } else if (strstr(name, "__not__")) { +	    Printv(pm, tab4, "\"!\" => sub { $_[0]->__not__()},\n",NIL); +	  } else if (strstr(name, "__lt__")) { +	    Printv(pm, tab4, "\"<\" => sub { $_[0]->__lt__($_[1])},\n",NIL); +          } else if (strstr(name, "__le__")) { +            Printv(pm, tab4, "\"<=\" => sub { $_[0]->__le__($_[1])},\n",NIL); +	  } else if (strstr(name, "__pluseq__")) { +	    Printv(pm, tab4, "\"+=\" => sub { $_[0]->__pluseq__($_[1])},\n",NIL); +	  } else if (strstr(name, "__mineq__")) { +	    Printv(pm, tab4, "\"-=\" => sub { $_[0]->__mineq__($_[1])},\n",NIL); +	  } else if (strstr(name, "__neg__")) { +	    Printv(pm, tab4, "\"neg\" => sub { $_[0]->__neg__()},\n",NIL); +	  } else { +	    fprintf(stderr,"Unknown operator: %s\n", name); +	  } +	} +	Printv(pm, tab4, +               "\"=\" => sub { my $class = ref($_[0]); $class->new($_[0]) },\n", NIL); +	Printv(pm, tab4, "\"fallback\" => 1;\n", NIL); +      } +      // make use strict happy +      Printv(pm, "use vars qw(@ISA %OWNER %ITERATORS %BLESSEDMEMBERS);\n", NIL); + +      /* If we are inheriting from a base class, set that up */ + +      Printv(pm, "@ISA = qw(", NIL); + +      /* Handle inheritance */ +      List *baselist = Getattr(n, "bases"); +      if (baselist && Len(baselist)) { +	Iterator b; +	b = First(baselist); +	while (b.item) { +	  String *bname = Getattr(b.item, "perl5:proxy"); +	  if (!bname) { +	    b = Next(b); +	    continue; +	  } +	  Printv(pm, " ", bname, NIL); +	  b = Next(b); +	} +      } + +      /* Module comes last */ +      if (!compat || Cmp(namespace_module, fullclassname)) { +	Printv(pm, " ", namespace_module, NIL); +      } + +      Printf(pm, " );\n"); + +      /* Dump out a hash table containing the pointers that we own */ +      Printf(pm, "%%OWNER = ();\n"); +      if (have_data_members || have_destructor) +	Printf(pm, "%%ITERATORS = ();\n"); + +      /* Dump out the package methods */ + +      Printv(pm, pcode, NIL); +      Delete(pcode); + +      /* Output methods for managing ownership */ + +      String *director_disown; +      if (Getattr(n, "perl5:directordisown")) { +	director_disown = NewStringf("%s%s($self);\n", tab4, Getattr(n, "perl5:directordisown")); +      } else { +	director_disown = NewString(""); +      } +      Printv(pm, +	     "sub DISOWN {\n", +	     tab4, "my $self = shift;\n", +	     director_disown, +	     tab4, "my $ptr = tied(%$self);\n", +	     tab4, "delete $OWNER{$ptr};\n", +	     "}\n\n", "sub ACQUIRE {\n", tab4, "my $self = shift;\n", tab4, "my $ptr = tied(%$self);\n", tab4, "$OWNER{$ptr} = 1;\n", "}\n\n", NIL); +      Delete(director_disown); + +      /* Only output the following methods if a class has member data */ + +      Delete(operators); +      operators = 0; +      if (Swig_directorclass(n)) { +	/* director classes need a way to recover subclass instance attributes */ +	Node *get_attr = NewHash(); +	String *mrename; +	String *symname = Getattr(n, "sym:name"); +	mrename = Swig_name_disown(NSPACE_TODO, symname); +	Replaceall(mrename, "disown", "swig_get_attr"); +	String *type = NewString(getClassType()); +	String *name = NewString("self"); +	SwigType_add_pointer(type); +	Parm *p = NewParm(type, name, n); +	Delete(name); +	Delete(type); +	type = NewString("SV"); +	SwigType_add_pointer(type); +	String *action = NewString(""); +	Printv(action, "{\n", "  Swig::Director *director = SWIG_DIRECTOR_CAST(arg1);\n", +	       "  result = sv_newmortal();\n" "  if (director) sv_setsv(result, director->swig_get_self());\n", "}\n", NIL); +	Setfile(get_attr, Getfile(n)); +	Setline(get_attr, Getline(n)); +	Setattr(get_attr, "wrap:action", action); +	Setattr(get_attr, "name", mrename); +	Setattr(get_attr, "sym:name", mrename); +	Setattr(get_attr, "type", type); +	Setattr(get_attr, "parms", p); +	Delete(action); +	Delete(type); +	Delete(p); + +	member_func = 1; +	functionWrapper(get_attr); +	member_func = 0; +	Delete(get_attr); + +	Printv(pm, "sub FETCH {\n", tab4, "my ($self,$field) = @_;\n", tab4, "my $member_func = \"swig_${field}_get\";\n", tab4, +	       "if (not $self->can($member_func)) {\n", tab8, "my $h = ", cmodule, "::", mrename, "($self);\n", tab8, "return $h->{$field} if $h;\n", +	       tab4, "}\n", tab4, "return $self->$member_func;\n", "}\n", "\n", "sub STORE {\n", tab4, "my ($self,$field,$newval) = @_;\n", tab4, +	       "my $member_func = \"swig_${field}_set\";\n", tab4, "if (not $self->can($member_func)) {\n", tab8, "my $h = ", cmodule, "::", mrename, +	       "($self);\n", tab8, "return $h->{$field} = $newval if $h;\n", tab4, "}\n", tab4, "return $self->$member_func($newval);\n", "}\n", NIL); + +	Delete(mrename); +      } +    } +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * memberfunctionHandler() +   * ------------------------------------------------------------ */ + +  virtual int memberfunctionHandler(Node *n) { +    String *symname = Getattr(n, "sym:name"); + +    member_func = 1; +    Language::memberfunctionHandler(n); +    member_func = 0; + +    if ((blessed) && (!Getattr(n, "sym:nextSibling"))) { + +      if (Strstr(symname, "__eq__")) { +	DohSetInt(operators, "__eq__", 1); +	have_operators = 1; +      } else if (Strstr(symname, "__ne__")) { +	DohSetInt(operators, "__ne__", 1); +	have_operators = 1; +      } else if (Strstr(symname, "__assign__")) { +	DohSetInt(operators, "__assign__", 1); +	have_operators = 1; +      } else if (Strstr(symname, "__str__")) { +	DohSetInt(operators, "__str__", 1); +	have_operators = 1; +      } else if (Strstr(symname, "__add__")) { +	DohSetInt(operators, "__add__", 1); +	have_operators = 1; +      } else if (Strstr(symname, "__sub__")) { +	DohSetInt(operators, "__sub__", 1); +	have_operators = 1; +      } else if (Strstr(symname, "__mul__")) { +	DohSetInt(operators, "__mul__", 1); +	have_operators = 1; +      } else if (Strstr(symname, "__div__")) { +	DohSetInt(operators, "__div__", 1); +	have_operators = 1; +      } else if (Strstr(symname, "__mod__")) { +	DohSetInt(operators, "__mod__", 1); +	have_operators = 1; +      } else if (Strstr(symname, "__and__")) { +	DohSetInt(operators, "__and__", 1); +	have_operators = 1; +      } else if (Strstr(symname, "__or__")) { +	DohSetInt(operators, "__or__", 1); +	have_operators = 1; +      } else if (Strstr(symname, "__not__")) { +	DohSetInt(operators, "__not__", 1); +	have_operators = 1; +      } else if (Strstr(symname, "__gt__")) { +	DohSetInt(operators, "__gt__", 1); +	have_operators = 1; +      } else if (Strstr(symname, "__ge__")) { +	DohSetInt(operators, "__ge__", 1); +	have_operators = 1; +      } else if (Strstr(symname, "__lt__")) { +	DohSetInt(operators, "__lt__", 1); +	have_operators = 1; +      } else if (Strstr(symname, "__le__")) { +	DohSetInt(operators, "__le__", 1); +	have_operators = 1; +      } else if (Strstr(symname, "__neg__")) { +	DohSetInt(operators, "__neg__", 1); +	have_operators = 1; +      } else if (Strstr(symname, "__plusplus__")) { +	DohSetInt(operators, "__plusplus__", 1); +	have_operators = 1; +      } else if (Strstr(symname, "__minmin__")) { +	DohSetInt(operators, "__minmin__", 1); +	have_operators = 1; +      } else if (Strstr(symname, "__mineq__")) { +	DohSetInt(operators, "__mineq__", 1); +	have_operators = 1; +      } else if (Strstr(symname, "__pluseq__")) { +	DohSetInt(operators, "__pluseq__", 1); +	have_operators = 1; +      } + +      if (Getattr(n, "feature:shadow")) { +	String *plcode = perlcode(Getattr(n, "feature:shadow"), 0); +	String *plaction = NewStringf("%s::%s", cmodule, Swig_name_member(NSPACE_TODO, class_name, symname)); +	Replaceall(plcode, "$action", plaction); +	Delete(plaction); +	Printv(pcode, plcode, NIL); +      } else { +	Printv(pcode, "*", symname, " = *", cmodule, "::", Swig_name_member(NSPACE_TODO, class_name, symname), ";\n", NIL); +      } +    } +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * membervariableHandler() +   * +   * Adds an instance member. +   * ----------------------------------------------------------------------------- */ + +  virtual int membervariableHandler(Node *n) { + +    String *symname = Getattr(n, "sym:name"); +    /* SwigType *t  = Getattr(n,"type"); */ + +    /* Emit a pair of get/set functions for the variable */ + +    member_func = 1; +    Language::membervariableHandler(n); +    member_func = 0; + +    if (blessed) { + +      Printv(pcode, "*swig_", symname, "_get = *", cmodule, "::", Swig_name_get(NSPACE_TODO, Swig_name_member(NSPACE_TODO, class_name, symname)), ";\n", NIL); +      Printv(pcode, "*swig_", symname, "_set = *", cmodule, "::", Swig_name_set(NSPACE_TODO, Swig_name_member(NSPACE_TODO, class_name, symname)), ";\n", NIL); + +      /* Now we need to generate a little Perl code for this */ + +      /* if (is_shadow(t)) { + +       *//* This is a Perl object that we have already seen.  Add an +         entry to the members list *//* +         Printv(blessedmembers, +         tab4, symname, " => '", is_shadow(t), "',\n", +         NIL); + +         } +       */ +    } +    have_data_members++; +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * constructorDeclaration() +   * +   * Emits a blessed constructor for our class.    In addition to our construct +   * we manage a Perl hash table containing all of the pointers created by +   * the constructor.   This prevents us from accidentally trying to free +   * something that wasn't necessarily allocated by malloc or new +   * ------------------------------------------------------------ */ + +  virtual int constructorHandler(Node *n) { + +    String *symname = Getattr(n, "sym:name"); + +    member_func = 1; + +    Swig_save("perl5:constructorHandler", n, "parms", NIL); +    if (Swig_directorclass(n)) { +      Parm *parms = Getattr(n, "parms"); +      Parm *self; +      String *name = NewString("self"); +      String *type = NewString("SV"); +      SwigType_add_pointer(type); +      self = NewParm(type, name, n); +      Delete(type); +      Delete(name); +      Setattr(self, "lname", "O"); +      if (parms) +	set_nextSibling(self, parms); +      Setattr(n, "parms", self); +      Setattr(n, "wrap:self", "1"); +      Setattr(n, "hidden", "1"); +      Delete(self); +    } + +    String *saved_nc = none_comparison; +    none_comparison = NewStringf("strcmp(SvPV_nolen(ST(0)), \"%s::%s\") != 0", module, class_name); +    String *saved_director_prot_ctor_code = director_prot_ctor_code; +    director_prot_ctor_code = NewStringf("if ($comparison) { /* subclassed */\n" "  $director_new\n" "} else {\n" +					 "SWIG_exception_fail(SWIG_RuntimeError, \"accessing abstract class or protected constructor\");\n" "}\n"); +    Language::constructorHandler(n); +    Delete(none_comparison); +    none_comparison = saved_nc; +    Delete(director_prot_ctor_code); +    director_prot_ctor_code = saved_director_prot_ctor_code; +    Swig_restore(n); + +    if ((blessed) && (!Getattr(n, "sym:nextSibling"))) { +      if (Getattr(n, "feature:shadow")) { +	String *plcode = perlcode(Getattr(n, "feature:shadow"), 0); +	String *plaction = NewStringf("%s::%s", module, Swig_name_member(NSPACE_TODO, class_name, symname)); +	Replaceall(plcode, "$action", plaction); +	Delete(plaction); +	Printv(pcode, plcode, NIL); +      } else { +	if ((Cmp(symname, class_name) == 0)) { +	  /* Emit a blessed constructor  */ +	  Printf(pcode, "sub new {\n"); +	} else { +	  /* Constructor doesn't match classname so we'll just use the normal name  */ +	  Printv(pcode, "sub ", Swig_name_construct(NSPACE_TODO, symname), " {\n", NIL); +	} + +	const char *pkg = getCurrentClass() && Swig_directorclass(getCurrentClass())? "$_[0]" : "shift"; +	Printv(pcode, +	       tab4, "my $pkg = ", pkg, ";\n", +	       tab4, "my $self = ", cmodule, "::", Swig_name_construct(NSPACE_TODO, symname), "(@_);\n", tab4, "bless $self, $pkg if defined($self);\n", "}\n\n", NIL); + +	have_constructor = 1; +      } +    } +    member_func = 0; +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------  +   * destructorHandler() +   * ------------------------------------------------------------ */ + +  virtual int destructorHandler(Node *n) { +    String *symname = Getattr(n, "sym:name"); +    member_func = 1; +    Language::destructorHandler(n); +    if (blessed) { +      if (Getattr(n, "feature:shadow")) { +	String *plcode = perlcode(Getattr(n, "feature:shadow"), 0); +	String *plaction = NewStringf("%s::%s", module, Swig_name_member(NSPACE_TODO, class_name, symname)); +	Replaceall(plcode, "$action", plaction); +	Delete(plaction); +	Printv(pcode, plcode, NIL); +      } else { +	Printv(pcode, +	       "sub DESTROY {\n", +	       tab4, "return unless $_[0]->isa('HASH');\n", +	       tab4, "my $self = tied(%{$_[0]});\n", +	       tab4, "return unless defined $self;\n", +	       tab4, "delete $ITERATORS{$self};\n", +	       tab4, "if (exists $OWNER{$self}) {\n", +	       tab8, cmodule, "::", Swig_name_destroy(NSPACE_TODO, symname), "($self);\n", tab8, "delete $OWNER{$self};\n", tab4, "}\n}\n\n", NIL); +	have_destructor = 1; +      } +    } +    member_func = 0; +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * staticmemberfunctionHandler() +   * ------------------------------------------------------------ */ + +  virtual int staticmemberfunctionHandler(Node *n) { +    member_func = 1; +    Language::staticmemberfunctionHandler(n); +    member_func = 0; +    if ((blessed) && (!Getattr(n, "sym:nextSibling"))) { +      String *symname = Getattr(n, "sym:name"); +      Printv(pcode, "*", symname, " = *", cmodule, "::", Swig_name_member(NSPACE_TODO, class_name, symname), ";\n", NIL); +    } +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * staticmembervariableHandler() +   * ------------------------------------------------------------ */ + +  virtual int staticmembervariableHandler(Node *n) { +    Language::staticmembervariableHandler(n); +    if (blessed) { +      String *symname = Getattr(n, "sym:name"); +      Printv(pcode, "*", symname, " = *", cmodule, "::", Swig_name_member(NSPACE_TODO, class_name, symname), ";\n", NIL); +    } +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * memberconstantHandler() +   * ------------------------------------------------------------ */ + +  virtual int memberconstantHandler(Node *n) { +    String *symname = Getattr(n, "sym:name"); +    int oldblessed = blessed; + +    /* Create a normal constant */ +    blessed = 0; +    Language::memberconstantHandler(n); +    blessed = oldblessed; + +    if (blessed) { +      Printv(pcode, "*", symname, " = *", cmodule, "::", Swig_name_member(NSPACE_TODO, class_name, symname), ";\n", NIL); +    } +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * pragma() +   * +   * Pragma directive. +   * +   * %pragma(perl5) code="String"              # Includes a string in the .pm file +   * %pragma(perl5) include="file.pl"          # Includes a file in the .pm file +   * ------------------------------------------------------------ */ + +  virtual int pragmaDirective(Node *n) { +    String *lang; +    String *code; +    String *value; +    if (!ImportMode) { +      lang = Getattr(n, "lang"); +      code = Getattr(n, "name"); +      value = Getattr(n, "value"); +      if (Strcmp(lang, "perl5") == 0) { +	if (Strcmp(code, "code") == 0) { +	  /* Dump the value string into the .pm file */ +	  if (value) { +	    Printf(pragma_include, "%s\n", value); +	  } +	} else if (Strcmp(code, "include") == 0) { +	  /* Include a file into the .pm file */ +	  if (value) { +	    FILE *f = Swig_include_open(value); +	    if (!f) { +	      Swig_error(input_file, line_number, "Unable to locate file %s\n", value); +	    } else { +	      char buffer[4096]; +	      while (fgets(buffer, 4095, f)) { +		Printf(pragma_include, "%s", buffer); +	      } +	      fclose(f); +	    } +	  } +	} else { +	  Swig_error(input_file, line_number, "Unrecognized pragma.\n"); +	} +      } +    } +    return Language::pragmaDirective(n); +  } + +  /* ------------------------------------------------------------ +   * perlcode()     - Output perlcode code into the shadow file +   * ------------------------------------------------------------ */ + +  String *perlcode(String *code, const String *indent) { +    String *out = NewString(""); +    String *temp; +    char *t; +    if (!indent) +      indent = ""; + +    temp = NewString(code); + +    t = Char(temp); +    if (*t == '{') { +      Delitem(temp, 0); +      Delitem(temp, DOH_END); +    } + +    /* Split the input text into lines */ +    List *clist = SplitLines(temp); +    Delete(temp); +    int initial = 0; +    String *s = 0; +    Iterator si; +    /* Get the initial indentation */ + +    for (si = First(clist); si.item; si = Next(si)) { +      s = si.item; +      if (Len(s)) { +	char *c = Char(s); +	while (*c) { +	  if (!isspace(*c)) +	    break; +	  initial++; +	  c++; +	} +	if (*c && !isspace(*c)) +	  break; +	else { +	  initial = 0; +	} +      } +    } +    while (si.item) { +      s = si.item; +      if (Len(s) > initial) { +	char *c = Char(s); +	c += initial; +	Printv(out, indent, c, "\n", NIL); +      } else { +	Printv(out, "\n", NIL); +      } +      si = Next(si); +    } +    Delete(clist); +    return out; +  } + +  /* ------------------------------------------------------------ +   * insertDirective() +   *  +   * Hook for %insert directive. +   * ------------------------------------------------------------ */ + +  virtual int insertDirective(Node *n) { +    String *code = Getattr(n, "code"); +    String *section = Getattr(n, "section"); + +    if ((!ImportMode) && (Cmp(section, "perl") == 0)) { +      Printv(additional_perl_code, code, NIL); +    } else { +      Language::insertDirective(n); +    } +    return SWIG_OK; +  } + +  String *runtimeCode() { +    String *s = NewString(""); +    String *shead = Swig_include_sys("perlhead.swg"); +    if (!shead) { +      Printf(stderr, "*** Unable to open 'perlhead.swg'\n"); +    } else { +      Append(s, shead); +      Delete(shead); +    } +    String *serrors = Swig_include_sys("perlerrors.swg"); +    if (!serrors) { +      Printf(stderr, "*** Unable to open 'perlerrors.swg'\n"); +    } else { +      Append(s, serrors); +      Delete(serrors); +    } +    String *srun = Swig_include_sys("perlrun.swg"); +    if (!srun) { +      Printf(stderr, "*** Unable to open 'perlrun.swg'\n"); +    } else { +      Append(s, srun); +      Delete(srun); +    } +    return s; +  } + +  String *defaultExternalRuntimeFilename() { +    return NewString("swigperlrun.h"); +  } + +  virtual int classDirectorInit(Node *n) { +    String *declaration = Swig_director_declaration(n); +    Printf(f_directors_h, "\n"); +    Printf(f_directors_h, "%s\n", declaration); +    Printf(f_directors_h, "public:\n"); +    Delete(declaration); +    return Language::classDirectorInit(n); +  } + +  virtual int classDirectorEnd(Node *n) { +    if (dirprot_mode()) { +      /* +         This implementation uses a std::map<std::string,int>. + +         It should be possible to rewrite it using a more elegant way, +         like copying the Java approach for the 'override' array. + +         But for now, this seems to be the least intrusive way. +       */ +      Printf(f_directors_h, "\n"); +      Printf(f_directors_h, "/* Internal director utilities */\n"); +      Printf(f_directors_h, "public:\n"); +      Printf(f_directors_h, "    bool swig_get_inner(const char *swig_protected_method_name) const {\n"); +      Printf(f_directors_h, "      std::map<std::string, bool>::const_iterator iv = swig_inner.find(swig_protected_method_name);\n"); +      Printf(f_directors_h, "      return (iv != swig_inner.end() ? iv->second : false);\n"); +      Printf(f_directors_h, "    }\n"); + +      Printf(f_directors_h, "    void swig_set_inner(const char *swig_protected_method_name, bool swig_val) const {\n"); +      Printf(f_directors_h, "      swig_inner[swig_protected_method_name] = swig_val;\n"); +      Printf(f_directors_h, "    }\n"); +      Printf(f_directors_h, "private:\n"); +      Printf(f_directors_h, "    mutable std::map<std::string, bool> swig_inner;\n"); +    } +    Printf(f_directors_h, "};\n"); +    return Language::classDirectorEnd(n); +  } + +  virtual int classDirectorConstructor(Node *n) { +    Node *parent = Getattr(n, "parentNode"); +    String *sub = NewString(""); +    String *decl = Getattr(n, "decl"); +    String *supername = Swig_class_name(parent); +    String *classname = NewString(""); +    Printf(classname, "SwigDirector_%s", supername); + +    /* insert self parameter */ +    Parm *p; +    ParmList *superparms = Getattr(n, "parms"); +    ParmList *parms = CopyParmList(superparms); +    String *type = NewString("SV"); +    SwigType_add_pointer(type); +    p = NewParm(type, NewString("self"), n); +    set_nextSibling(p, parms); +    parms = p; + +    if (!Getattr(n, "defaultargs")) { +      /* constructor */ +      { +	Wrapper *w = NewWrapper(); +	String *call; +	String *basetype = Getattr(parent, "classtype"); +	String *target = Swig_method_decl(0, decl, classname, parms, 0); +	call = Swig_csuperclass_call(0, basetype, superparms); +	Printf(w->def, "%s::%s: %s, Swig::Director(self) { \n", classname, target, call); +	Printf(w->def, "   SWIG_DIRECTOR_RGTR((%s *)this, this); \n", basetype); +	Append(w->def, "}\n"); +	Delete(target); +	Wrapper_print(w, f_directors); +	Delete(call); +	DelWrapper(w); +      } + +      /* constructor header */ +      { +	String *target = Swig_method_decl(0, decl, classname, parms, 1); +	Printf(f_directors_h, "    %s;\n", target); +	Delete(target); +      } +    } + +    Delete(sub); +    Delete(classname); +    Delete(supername); +    Delete(parms); +    return Language::classDirectorConstructor(n); +  } + +  virtual int classDirectorMethod(Node *n, Node *parent, String *super) { +    int is_void = 0; +    int is_pointer = 0; +    String *decl = Getattr(n, "decl"); +    String *name = Getattr(n, "name"); +    String *classname = Getattr(parent, "sym:name"); +    String *c_classname = Getattr(parent, "name"); +    String *symname = Getattr(n, "sym:name"); +    String *declaration = NewString(""); +    ParmList *l = Getattr(n, "parms"); +    Wrapper *w = NewWrapper(); +    String *tm; +    String *wrap_args = NewString(""); +    String *returntype = Getattr(n, "type"); +    String *value = Getattr(n, "value"); +    String *storage = Getattr(n, "storage"); +    bool pure_virtual = false; +    int status = SWIG_OK; +    int idx; +    bool ignored_method = GetFlag(n, "feature:ignore") ? true : false; + +    if (Cmp(storage, "virtual") == 0) { +      if (Cmp(value, "0") == 0) { +	pure_virtual = true; +      } +    } + +    /* determine if the method returns a pointer */ +    is_pointer = SwigType_ispointer_return(decl); +    is_void = (!Cmp(returntype, "void") && !is_pointer); + +    /* virtual method definition */ +    String *target; +    String *pclassname = NewStringf("SwigDirector_%s", classname); +    String *qualified_name = NewStringf("%s::%s", pclassname, name); +    SwigType *rtype = Getattr(n, "conversion_operator") ? 0 : Getattr(n, "classDirectorMethods:type"); +    target = Swig_method_decl(rtype, decl, qualified_name, l, 0); +    Printf(w->def, "%s", target); +    Delete(qualified_name); +    Delete(target); +    /* header declaration */ +    target = Swig_method_decl(rtype, decl, name, l, 1); +    Printf(declaration, "    virtual %s", target); +    Delete(target); + +    // Get any exception classes in the throws typemap +    if (Getattr(n, "noexcept")) { +      Append(w->def, " noexcept"); +      Append(declaration, " noexcept"); +    } +    ParmList *throw_parm_list = 0; + +    if ((throw_parm_list = Getattr(n, "throws")) || Getattr(n, "throw")) { +      Parm *p; +      int gencomma = 0; + +      Append(w->def, " throw("); +      Append(declaration, " throw("); + +      if (throw_parm_list) +	Swig_typemap_attach_parms("throws", throw_parm_list, 0); +      for (p = throw_parm_list; p; p = nextSibling(p)) { +	if (Getattr(p, "tmap:throws")) { +	  if (gencomma++) { +	    Append(w->def, ", "); +	    Append(declaration, ", "); +	  } +	  String *str = SwigType_str(Getattr(p, "type"), 0); +	  Append(w->def, str); +	  Append(declaration, str); +	  Delete(str); +	} +      } + +      Append(w->def, ")"); +      Append(declaration, ")"); +    } + +    Append(w->def, " {"); +    Append(declaration, ";\n"); + +    /* declare method return value  +     * if the return value is a reference or const reference, a specialized typemap must +     * handle it, including declaration of c_result ($result). +     */ +    if (!is_void && (!ignored_method || pure_virtual)) { +      if (!SwigType_isclass(returntype)) { +	if (!(SwigType_ispointer(returntype) || SwigType_isreference(returntype))) { +	  String *construct_result = NewStringf("= SwigValueInit< %s >()", SwigType_lstr(returntype, 0)); +	  Wrapper_add_localv(w, "c_result", SwigType_lstr(returntype, "c_result"), construct_result, NIL); +	  Delete(construct_result); +	} else { +	  Wrapper_add_localv(w, "c_result", SwigType_lstr(returntype, "c_result"), "= 0", NIL); +	} +      } else { +	String *cres = SwigType_lstr(returntype, "c_result"); +	Printf(w->code, "%s;\n", cres); +	Delete(cres); +      } +    } + +    if (!is_void && !ignored_method) { +      String *pres = NewStringf("SV *%s", Swig_cresult_name()); +      Wrapper_add_local(w, Swig_cresult_name(), pres); +      Delete(pres); +    } + +    if (ignored_method) { +      if (!pure_virtual) { +	if (!is_void) +	  Printf(w->code, "return "); +	String *super_call = Swig_method_call(super, l); +	Printf(w->code, "%s;\n", super_call); +	Delete(super_call); +      } else { +	Printf(w->code, "Swig::DirectorPureVirtualException::raise(\"Attempted to invoke pure virtual method %s::%s\");\n", SwigType_namestr(c_classname), +	       SwigType_namestr(name)); +      } +    } else { +      /* attach typemaps to arguments (C/C++ -> Perl) */ +      String *parse_args = NewString(""); +      String *pstack = NewString(""); + +      Swig_director_parms_fixup(l); + +      /* remove the wrapper 'w' since it was producing spurious temps */ +      Swig_typemap_attach_parms("in", l, 0); +      Swig_typemap_attach_parms("directorin", l, w); +      Swig_typemap_attach_parms("directorargout", l, w); + +      Wrapper_add_local(w, "SP", "dSP"); + +      { +	String *ptype = Copy(getClassType()); +	SwigType_add_pointer(ptype); +	String *mangle = SwigType_manglestr(ptype); + +	Wrapper_add_local(w, "swigself", "SV *swigself"); +	Printf(w->code, "swigself = SWIG_NewPointerObj(SWIG_as_voidptr(this), SWIGTYPE%s, SWIG_SHADOW);\n", mangle); +	Printf(w->code, "sv_bless(swigself, gv_stashpv(swig_get_class(), 0));\n"); +	Delete(mangle); +	Delete(ptype); +	Append(pstack, "XPUSHs(swigself);\n"); +      } + +      Parm *p; +      char source[256]; + +      int outputs = 0; +      if (!is_void) +	outputs++; + +      /* build argument list and type conversion string */ +      idx = 0; +      p = l; +      while (p) { +	if (checkAttribute(p, "tmap:in:numinputs", "0")) { +	  p = Getattr(p, "tmap:in:next"); +	  continue; +	} + +	/* old style?  caused segfaults without the p!=0 check +	   in the for() condition, and seems dangerous in the +	   while loop as well. +	   while (Getattr(p, "tmap:ignore")) { +	   p = Getattr(p, "tmap:ignore:next"); +	   } +	 */ + +	if (Getattr(p, "tmap:directorargout") != 0) +	  outputs++; + +	String *pname = Getattr(p, "name"); +	String *ptype = Getattr(p, "type"); + +	if ((tm = Getattr(p, "tmap:directorin")) != 0) { +	  sprintf(source, "obj%d", idx++); +	  String *input = NewString(source); +	  Setattr(p, "emit:directorinput", input); +	  Replaceall(tm, "$input", input); +	  Delete(input); +	  Replaceall(tm, "$owner", "0"); +	  Replaceall(tm, "$shadow", "0"); +	  /* Wrapper_add_localv(w, source, "SV *", source, "= 0", NIL); */ +	  Printv(wrap_args, "SV *", source, ";\n", NIL); + +	  Printv(wrap_args, tm, "\n", NIL); +	  Putc('O', parse_args); +	  Printv(pstack, "XPUSHs(", source, ");\n", NIL); +	  p = Getattr(p, "tmap:directorin:next"); +	  continue; +	} else if (Cmp(ptype, "void")) { +	  /* special handling for pointers to other C++ director classes. +	   * ideally this would be left to a typemap, but there is currently no +	   * way to selectively apply the dynamic_cast<> to classes that have +	   * directors.  in other words, the type "SwigDirector_$1_lname" only exists +	   * for classes with directors.  we avoid the problem here by checking +	   * module.wrap::directormap, but it's not clear how to get a typemap to +	   * do something similar.  perhaps a new default typemap (in addition +	   * to SWIGTYPE) called DIRECTORTYPE? +	   */ +	  if (SwigType_ispointer(ptype) || SwigType_isreference(ptype)) { +	    Node *module = Getattr(parent, "module"); +	    Node *target = Swig_directormap(module, ptype); +	    sprintf(source, "obj%d", idx++); +	    String *nonconst = 0; +	    /* strip pointer/reference --- should move to Swig/stype.c */ +	    String *nptype = NewString(Char(ptype) + 2); +	    /* name as pointer */ +	    String *ppname = Copy(pname); +	    if (SwigType_isreference(ptype)) { +	      Insert(ppname, 0, "&"); +	    } +	    /* if necessary, cast away const since Perl doesn't support it! */ +	    if (SwigType_isconst(nptype)) { +	      nonconst = NewStringf("nc_tmp_%s", pname); +	      String *nonconst_i = NewStringf("= const_cast< %s >(%s)", SwigType_lstr(ptype, 0), ppname); +	      Wrapper_add_localv(w, nonconst, SwigType_lstr(ptype, 0), nonconst, nonconst_i, NIL); +	      Delete(nonconst_i); +	      Swig_warning(WARN_LANG_DISCARD_CONST, input_file, line_number, +			   "Target language argument '%s' discards const in director method %s::%s.\n", +			   SwigType_str(ptype, pname), SwigType_namestr(c_classname), SwigType_namestr(name)); +	    } else { +	      nonconst = Copy(ppname); +	    } +	    Delete(nptype); +	    Delete(ppname); +	    String *mangle = SwigType_manglestr(ptype); +	    if (target) { +	      String *director = NewStringf("director_%s", mangle); +	      Wrapper_add_localv(w, director, "Swig::Director *", director, "= 0", NIL); +	      Wrapper_add_localv(w, source, "SV *", source, "= 0", NIL); +	      Printf(wrap_args, "%s = SWIG_DIRECTOR_CAST(%s);\n", director, nonconst); +	      Printf(wrap_args, "if (!%s) {\n", director); +	      Printf(wrap_args, "%s = SWIG_NewPointerObj(%s, SWIGTYPE%s, 0);\n", source, nonconst, mangle); +	      Append(wrap_args, "} else {\n"); +	      Printf(wrap_args, "%s = %s->swig_get_self();\n", source, director); +	      Printf(wrap_args, "SvREFCNT_inc((SV *)%s);\n", source); +	      Append(wrap_args, "}\n"); +	      Delete(director); +	    } else { +	      Wrapper_add_localv(w, source, "SV *", source, "= 0", NIL); +	      Printf(wrap_args, "%s = SWIG_NewPointerObj(%s, SWIGTYPE%s, 0);\n", source, nonconst, mangle); +	      Printf(pstack, "XPUSHs(sv_2mortal(%s));\n", source); +	    } +	    Putc('O', parse_args); +	    Delete(mangle); +	    Delete(nonconst); +	  } else { +	    Swig_warning(WARN_TYPEMAP_DIRECTORIN_UNDEF, input_file, line_number, +			 "Unable to use type %s as a function argument in director method %s::%s (skipping method).\n", SwigType_str(ptype, 0), +			 SwigType_namestr(c_classname), SwigType_namestr(name)); +	    status = SWIG_NOWRAP; +	    break; +	  } +	} +	p = nextSibling(p); +      } + +      /* add the method name as a PyString */ +      String *pyname = Getattr(n, "sym:name"); + +      /* wrap complex arguments to PyObjects */ +      Printv(w->code, wrap_args, NIL); + +      /* pass the method call on to the Python object */ +      if (dirprot_mode() && !is_public(n)) { +	Printf(w->code, "swig_set_inner(\"%s\", true);\n", name); +      } + +      Append(w->code, "ENTER;\n"); +      Append(w->code, "SAVETMPS;\n"); +      Append(w->code, "PUSHMARK(SP);\n"); +      Append(w->code, pstack); +      Delete(pstack); +      Append(w->code, "PUTBACK;\n"); +      Printf(w->code, "call_method(\"%s\", G_EVAL | G_SCALAR);\n", pyname); + +      if (dirprot_mode() && !is_public(n)) +	Printf(w->code, "swig_set_inner(\"%s\", false);\n", name); + +      /* exception handling */ +      tm = Swig_typemap_lookup("director:except", n, Swig_cresult_name(), 0); +      if (!tm) { +	tm = Getattr(n, "feature:director:except"); +	if (tm) +	  tm = Copy(tm); +      } +      Append(w->code, "if (SvTRUE(ERRSV)) {\n"); +      Append(w->code, "  PUTBACK;\n  FREETMPS;\n  LEAVE;\n"); +      if ((tm) && Len(tm) && (Strcmp(tm, "1") != 0)) { +	Replaceall(tm, "$error", "ERRSV"); +	Printv(w->code, Str(tm), "\n", NIL); +      } else { +	Printf(w->code, "  Swig::DirectorMethodException::raise(ERRSV);\n"); +      } +      Append(w->code, "}\n"); +      Delete(tm); + +      /* +       * Python method may return a simple object, or a tuple. +       * for in/out arguments, we have to extract the appropriate PyObjects from the tuple, +       * then marshal everything back to C/C++ (return value and output arguments). +       * +       */ + +      /* marshal return value and other outputs (if any) from PyObject to C/C++ type */ + +      String *cleanup = NewString(""); +      String *outarg = NewString(""); + +      if (outputs > 1) { +	Wrapper_add_local(w, "output", "SV *output"); +	Printf(w->code, "if (count != %d) {\n", outputs); +	Printf(w->code, "  Swig::DirectorTypeMismatchException::raise(\"Perl method %s.%sfailed to return a list.\");\n", classname, pyname); +	Append(w->code, "}\n"); +      } + +      idx = 0; + +      /* marshal return value */ +      if (!is_void) { +	Append(w->code, "SPAGAIN;\n"); +	Printf(w->code, "%s = POPs;\n", Swig_cresult_name()); +	tm = Swig_typemap_lookup("directorout", n, Swig_cresult_name(), w); +	if (tm != 0) { +	  if (outputs > 1) { +	    Printf(w->code, "output = POPs;\n"); +	    Replaceall(tm, "$input", "output"); +	  } else { +	    Replaceall(tm, "$input", Swig_cresult_name()); +	  } +	  char temp[24]; +	  sprintf(temp, "%d", idx); +	  Replaceall(tm, "$argnum", temp); + +	  /* TODO check this */ +	  if (Getattr(n, "wrap:disown")) { +	    Replaceall(tm, "$disown", "SWIG_POINTER_DISOWN"); +	  } else { +	    Replaceall(tm, "$disown", "0"); +	  } +	  Replaceall(tm, "$result", "c_result"); +	  Printv(w->code, tm, "\n", NIL); +	  Delete(tm); +	} else { +	  Swig_warning(WARN_TYPEMAP_DIRECTOROUT_UNDEF, input_file, line_number, +		       "Unable to use return type %s in director method %s::%s (skipping method).\n", SwigType_str(returntype, 0), +		       SwigType_namestr(c_classname), SwigType_namestr(name)); +	  status = SWIG_ERROR; +	} +      } + +      /* marshal outputs */ +      for (p = l; p;) { +	if ((tm = Getattr(p, "tmap:directorargout")) != 0) { +	  if (outputs > 1) { +	    Printf(w->code, "output = POPs;\n"); +	    Replaceall(tm, "$result", "output"); +	  } else { +	    Replaceall(tm, "$result", Swig_cresult_name()); +	  } +	  Replaceall(tm, "$input", Getattr(p, "emit:directorinput")); +	  Printv(w->code, tm, "\n", NIL); +	  p = Getattr(p, "tmap:directorargout:next"); +	} else { +	  p = nextSibling(p); +	} +      } + +      Delete(parse_args); +      Delete(cleanup); +      Delete(outarg); +    } + +    if (!ignored_method) { +      Append(w->code, "PUTBACK;\n"); +      Append(w->code, "FREETMPS;\n"); +      Append(w->code, "LEAVE;\n"); +    } + +    if (!is_void) { +      if (!(ignored_method && !pure_virtual)) { +	String *rettype = SwigType_str(returntype, 0); +	if (!SwigType_isreference(returntype)) { +	  Printf(w->code, "return (%s) c_result;\n", rettype); +	} else { +	  Printf(w->code, "return (%s) *c_result;\n", rettype); +	} +	Delete(rettype); +      } +    } + +    Append(w->code, "}\n"); + +    // We expose protected methods via an extra public inline method which makes a straight call to the wrapped class' method +    String *inline_extra_method = NewString(""); +    if (dirprot_mode() && !is_public(n) && !pure_virtual) { +      Printv(inline_extra_method, declaration, NIL); +      String *extra_method_name = NewStringf("%sSwigPublic", name); +      Replaceall(inline_extra_method, name, extra_method_name); +      Replaceall(inline_extra_method, ";\n", " {\n      "); +      if (!is_void) +	Printf(inline_extra_method, "return "); +      String *methodcall = Swig_method_call(super, l); +      Printv(inline_extra_method, methodcall, ";\n    }\n", NIL); +      Delete(methodcall); +      Delete(extra_method_name); +    } + +    /* emit the director method */ +    if (status == SWIG_OK) { +      if (!Getattr(n, "defaultargs")) { +	Replaceall(w->code, "$symname", symname); +	Wrapper_print(w, f_directors); +	Printv(f_directors_h, declaration, NIL); +	Printv(f_directors_h, inline_extra_method, NIL); +      } +    } + +    /* clean up */ +    Delete(wrap_args); +    Delete(pclassname); +    DelWrapper(w); +    return status; +  } +  int classDirectorDisown(Node *n) { +    int rv; +    member_func = 1; +    rv = Language::classDirectorDisown(n); +    member_func = 0; +    if (rv == SWIG_OK && Swig_directorclass(n)) { +      String *symname = Getattr(n, "sym:name"); +      String *disown = Swig_name_disown(NSPACE_TODO, symname); +      Setattr(n, "perl5:directordisown", NewStringf("%s::%s", cmodule, disown)); +    } +    return rv; +  } +  int classDirectorDestructor(Node *n) { +    /* TODO: it would be nice if this didn't have to copy the body of Language::classDirectorDestructor() */ +    String *DirectorClassName = directorClassName(getCurrentClass()); +    String *body = NewString("\n"); + +    String *ptype = Copy(getClassType()); +    SwigType_add_pointer(ptype); +    String *mangle = SwigType_manglestr(ptype); + +    Printv(body, tab4, "dSP;\n", tab4, "SV *self = SWIG_NewPointerObj(SWIG_as_voidptr(this), SWIGTYPE", mangle, ", SWIG_SHADOW);\n", tab4, "\n", tab4, +	   "sv_bless(self, gv_stashpv(swig_get_class(), 0));\n", tab4, "ENTER;\n", tab4, "SAVETMPS;\n", tab4, "PUSHMARK(SP);\n", tab4, +	   "XPUSHs(self);\n", tab4, "XPUSHs(&PL_sv_yes);\n", tab4, "PUTBACK;\n", tab4, "call_method(\"DESTROY\", G_EVAL | G_VOID);\n", tab4, +	   "FREETMPS;\n", tab4, "LEAVE;\n", NIL); + +    Delete(mangle); +    Delete(ptype); + +    if (Getattr(n, "noexcept")) { +      Printf(f_directors_h, "    virtual ~%s() noexcept;\n", DirectorClassName); +      Printf(f_directors, "%s::~%s() noexcept {%s}\n\n", DirectorClassName, DirectorClassName, body); +    } else if (Getattr(n, "throw")) { +      Printf(f_directors_h, "    virtual ~%s() throw();\n", DirectorClassName); +      Printf(f_directors, "%s::~%s() throw() {%s}\n\n", DirectorClassName, DirectorClassName, body); +    } else { +      Printf(f_directors_h, "    virtual ~%s();\n", DirectorClassName); +      Printf(f_directors, "%s::~%s() {%s}\n\n", DirectorClassName, DirectorClassName, body); +    } +    return SWIG_OK; +  } +}; + +/* ----------------------------------------------------------------------------- + * swig_perl5()    - Instantiate module + * ----------------------------------------------------------------------------- */ + +static Language *new_swig_perl5() { +  return new PERL5(); +} +extern "C" Language *swig_perl5(void) { +  return new_swig_perl5(); +} diff --git a/contrib/tools/swig/Source/Modules/php.cxx b/contrib/tools/swig/Source/Modules/php.cxx new file mode 100644 index 00000000000..c8cc9212b11 --- /dev/null +++ b/contrib/tools/swig/Source/Modules/php.cxx @@ -0,0 +1,2702 @@ +/* ----------------------------------------------------------------------------- + * This file is part of SWIG, which is licensed as a whole under version 3 + * (or any later version) of the GNU General Public License. Some additional + * terms also apply to certain portions of SWIG. The full details of the SWIG + * license and copyrights can be found in the LICENSE and COPYRIGHT files + * included with the SWIG source code as distributed by the SWIG developers + * and at https://www.swig.org/legal.html. + * + * php.cxx + * + * PHP language module for SWIG. + * ----------------------------------------------------------------------------- + */ + +#include "swigmod.h" +#include <algorithm> +#include <ctype.h> +#include <errno.h> +#include <limits.h> + +static const char *usage = "\ +PHP Options (available with -php7)\n\ +     -prefix <prefix> - Prepend <prefix> to all class names in PHP wrappers\n\ +\n"; + +// How to wrap non-class functions, variables and constants: +// FIXME: Make this specifiable and also allow a real namespace. + +// Wrap as global PHP names. +static bool wrap_nonclass_global = true; + +// Wrap in a class to fake a namespace (for compatibility with SWIG's behaviour +// before PHP added namespaces. +static bool wrap_nonclass_fake_class = true; + +static String *module = 0; +static String *cap_module = 0; +static String *prefix = 0; + +static File *f_begin = 0; +static File *f_runtime = 0; +static File *f_runtime_h = 0; +static File *f_h = 0; +static File *f_directors = 0; +static File *f_directors_h = 0; + +static String *s_header; +static String *s_wrappers; +static String *s_init; +static String *r_init;		// RINIT user code +static String *s_shutdown;	// MSHUTDOWN user code +static String *r_shutdown;	// RSHUTDOWN user code +static String *s_vdecl; +static String *s_cinit;		// consttab initialization code. +static String *s_oinit; +static String *s_arginfo; +static String *s_entry; +static String *cs_entry; +static String *all_cs_entry; +static String *fake_cs_entry; +static String *s_creation; +static String *pragma_incl; +static String *pragma_code; +static String *pragma_phpinfo; +static String *pragma_version; + +static String *class_name = NULL; +static String *base_class = NULL; +static String *destructor_action = NULL; +static String *magic_set = NULL; +static String *magic_get = NULL; +static String *magic_isset = NULL; + +// Class used as pseudo-namespace for compatibility. +static String *fake_class_name() { +  static String *result = NULL; +  if (!result) { +    result = Len(prefix) ? prefix : module; +    if (!fake_cs_entry) { +      fake_cs_entry = NewStringf("static const zend_function_entry class_%s_functions[] = {\n", result); +    } + +    Printf(s_creation, "static zend_class_entry *SWIG_Php_ce_%s;\n\n",result); + +    Printf(s_oinit, "  INIT_CLASS_ENTRY(internal_ce, \"%s\", class_%s_functions);\n", result, result); +    Printf(s_oinit, "  SWIG_Php_ce_%s = zend_register_internal_class(&internal_ce);\n", result); +    Printf(s_oinit, "\n"); +  } +  return result; +} + +static String *swig_wrapped_interface_ce() { +  static String *result = NULL; +  if (!result) { +    result = NewStringf("SWIG_Php_swig_wrapped_interface_ce"); +    Printf(s_oinit, "  INIT_CLASS_ENTRY(%s, \"SWIG\\\\wrapped\", NULL);\n", result); +  } +  return result; +} + +/* To reduce code size (generated and compiled) we only want to emit each + * different arginfo once, so we need to track which have been used. + */ +static Hash *arginfo_used; + +/* Track non-class pointer types we need to to wrap */ +static Hash *raw_pointer_types = 0; + +static int shadow = 1; + +// These static variables are used to pass some state from Handlers into functionWrapper +static enum { +  standard = 0, +  memberfn, +  staticmemberfn, +  membervar, +  staticmembervar, +  constructor, +  destructor, +  directorconstructor, +  directordisown +} wrapperType = standard; + +extern "C" { +  static void (*r_prevtracefunc) (const SwigType *t, String *mangled, String *clientdata) = 0; +} + +static void SwigPHP_emit_pointer_type_registrations() { +  if (!raw_pointer_types) +    return; + +  Iterator ki = First(raw_pointer_types); +  if (!ki.key) +    return; + +  Printf(s_wrappers, "/* class object handlers for pointer wrappers */\n"); +  Printf(s_wrappers, "static zend_object_handlers swig_ptr_object_handlers;\n\n"); + +  Printf(s_wrappers, "/* Object Creation Method for pointer wrapping class */\n"); +  Printf(s_wrappers, "static zend_object *swig_ptr_object_new(zend_class_entry *ce) {\n"); +  Printf(s_wrappers, "  swig_object_wrapper *obj = (swig_object_wrapper*)zend_object_alloc(sizeof(swig_object_wrapper), ce);\n"); +  Printf(s_wrappers, "  zend_object_std_init(&obj->std, ce);\n"); +  Printf(s_wrappers, "  object_properties_init(&obj->std, ce);\n"); +  Printf(s_wrappers, "  obj->std.handlers = &swig_ptr_object_handlers;\n"); +  Printf(s_wrappers, "  obj->newobject = 0;\n"); +  Printf(s_wrappers, "  return &obj->std;\n"); +  Printf(s_wrappers, "}\n\n"); + +  Printf(s_wrappers, "/* Implement __toString equivalent, since that worked for the old-style resource wrapped pointers. */\n"); +  Append(s_wrappers, "#if PHP_MAJOR_VERSION < 8\n"); +  Printf(s_wrappers, "static int swig_ptr_cast_object(zval *z, zval *retval, int type) {\n"); +  Append(s_wrappers, "#elif PHP_MAJOR_VERSION > 8 || PHP_MINOR_VERSION >= 2\n"); +  Printf(s_wrappers, "static ZEND_RESULT_CODE swig_ptr_cast_object(zend_object *zobj, zval *retval, int type) {\n"); +  Append(s_wrappers, "#else\n"); +  Printf(s_wrappers, "static int swig_ptr_cast_object(zend_object *zobj, zval *retval, int type) {\n"); +  Append(s_wrappers, "#endif\n"); +  Printf(s_wrappers, "  if (type == IS_STRING) {\n"); +  Append(s_wrappers, "#if PHP_MAJOR_VERSION < 8\n"); +  Printf(s_wrappers, "    swig_object_wrapper *obj = SWIG_Z_FETCH_OBJ_P(z);\n"); +  Append(s_wrappers, "#else\n"); +  Printf(s_wrappers, "    swig_object_wrapper *obj = swig_php_fetch_object(zobj);\n"); +  Append(s_wrappers, "#endif\n"); +  Printv(s_wrappers, "    ZVAL_NEW_STR(retval, zend_strpprintf(0, \"SWIGPointer(%p,owned=%d)\", obj->ptr, obj->newobject));\n", NIL); +  Printf(s_wrappers, "    return SUCCESS;\n"); +  Printf(s_wrappers, "  }\n"); +  Printf(s_wrappers, "  return FAILURE;\n"); +  Printf(s_wrappers, "}\n\n"); + +  Printf(s_oinit, "\n  /* Register classes to represent non-class pointer types */\n"); +  Printf(s_oinit, "  swig_ptr_object_handlers = *zend_get_std_object_handlers();\n"); +  Printf(s_oinit, "  swig_ptr_object_handlers.offset = XtOffsetOf(swig_object_wrapper, std);\n"); +  Printf(s_oinit, "  swig_ptr_object_handlers.cast_object = swig_ptr_cast_object;\n"); + +  while (ki.key) { +    String *type = ki.key; + +    String *swig_wrapped = swig_wrapped_interface_ce(); +    Printf(s_creation, "/* class entry for pointer to %s */\n", type); +    Printf(s_creation, "static zend_class_entry *SWIG_Php_ce_%s;\n\n", type); + +    Printf(s_oinit, "  INIT_CLASS_ENTRY(internal_ce, \"%s\\\\%s\", NULL);\n", "SWIG", type); +    Printf(s_oinit, "  SWIG_Php_ce_%s = zend_register_internal_class(&internal_ce);\n", type); +    Printf(s_oinit, "  SWIG_Php_ce_%s->create_object = swig_ptr_object_new;\n", type); +    Printv(s_oinit, "  zend_do_implement_interface(SWIG_Php_ce_", type, ", &", swig_wrapped, ");\n", NIL); +    Printf(s_oinit, "  SWIG_TypeClientData(SWIGTYPE%s,SWIG_Php_ce_%s);\n", type, type); +    Printf(s_oinit, "\n"); + +    ki = Next(ki); +  } +} + +static Hash *create_php_type_flags() { +  Hash *h = NewHash(); +  Setattr(h, "array", "MAY_BE_ARRAY"); +  Setattr(h, "bool", "MAY_BE_BOOL"); +  Setattr(h, "callable", "MAY_BE_CALLABLE"); +  Setattr(h, "float", "MAY_BE_DOUBLE"); +  Setattr(h, "int", "MAY_BE_LONG"); +  Setattr(h, "iterable", "MAY_BE_ITERABLE"); +  Setattr(h, "mixed", "MAY_BE_MIXED"); +  Setattr(h, "null", "MAY_BE_NULL"); +  Setattr(h, "object", "MAY_BE_OBJECT"); +  Setattr(h, "resource", "MAY_BE_RESOURCE"); +  Setattr(h, "string", "MAY_BE_STRING"); +  Setattr(h, "void", "MAY_BE_VOID"); +  return h; +} + +static Hash *php_type_flags = create_php_type_flags(); + +// php_class + ":" + php_method -> PHPTypes* +// ":" + php_function -> PHPTypes* +static Hash *all_phptypes = NewHash(); + +// php_class_name -> php_parent_class_name +static Hash *php_parent_class = NewHash(); + +// Track if a method is directed in a descendent class. +// php_class + ":" + php_method -> boolean (using SetFlag()/GetFlag()). +static Hash *has_directed_descendent = NewHash(); + +// Track required return type for parent class methods. +// php_class + ":" + php_method -> List of php types. +static Hash *parent_class_method_return_type = NewHash(); + +// Class encapsulating the machinery to add PHP type declarations. +class PHPTypes { +  // List with an entry for each parameter and one for the return type. +  // +  // We assemble the types in here before emitting them so for an overloaded +  // function we combine the type declarations from each overloaded form. +  List *merged_types; + +  // List with an entry for each parameter which is passed "byref" in any +  // overloaded form.  We use this to pass such parameters by reference in +  // the dispatch function.  If NULL, no parameters are passed by reference. +  List *byref; + +  // The id string used in the name of the arginfo for this object. +  String *arginfo_id; + +  // The feature:php:type value: 0, 1 or -1 for "compatibility". +  int php_type_flag; + +  // Does the node for this have directorNode set? +  bool has_director_node; + +  // Used to clamp the required number of parameters in the arginfo to be +  // compatible with any parent class version of the method. +  int num_required; + +  int get_byref(int key) const { +    return byref && key < Len(byref) && Getitem(byref, key) != None; +  } + +  int size() const { +    return std::max(Len(merged_types), Len(byref)); +  } + +  String *get_phptype(int key, String *classtypes, List *more_return_types = NULL) { +    Clear(classtypes); +    // We want to minimise the list of class types by not redundantly listing +    // a class for which a super-class is also listed.  This canonicalisation +    // allows for more sharing of arginfo (which reduces module size), makes +    // for a cleaner list if it's shown to the user, and also will speed up +    // module load a bit. +    Hash *classes = NewHash(); +    DOH *types = Getitem(merged_types, key); +    String *result = NewStringEmpty(); +    if (more_return_types) { +      if (types != None) { +	merge_type_lists(types, more_return_types); +      } +    } +    if (types != None) { +      SortList(types, NULL); +      String *prev = NULL; +      for (Iterator i = First(types); i.item; i = Next(i)) { +	if (prev && Equal(prev, i.item)) { +	  // Skip duplicates when merging. +	  continue; +	} +	String *c = Getattr(php_type_flags, i.item); +	if (c) { +	  if (Len(result) > 0) Append(result, "|"); +	  Append(result, c); +	} else { +	  SetFlag(classes, i.item); +	} +	prev = i.item; +      } +    } + +    // Remove entries for which a super-class is also listed. +    Iterator i = First(classes); +    while (i.key) { +      String *this_class = i.key; +      // We must advance the iterator early so we don't delete the element it +      // points to. +      i = Next(i); +      String *parent = this_class; +      while ((parent = Getattr(php_parent_class, parent)) != NULL) { +	if (GetFlag(classes, parent)) { +	  Delattr(classes, this_class); +	  break; +	} +      } +    } + +    List *sorted_classes = SortedKeys(classes, Strcmp); +    for (i = First(sorted_classes); i.item; i = Next(i)) { +      if (Len(classtypes) > 0) Append(classtypes, "|"); +      Append(classtypes, prefix); +      Append(classtypes, i.item); +    } +    Delete(sorted_classes); + +    // Make the mask 0 if there are only class names specified. +    if (Len(result) == 0) { +      Append(result, "0"); +    } +    return result; +  } + +public: +  PHPTypes(Node *n) +    : merged_types(NewList()), +      byref(NULL), +      num_required(INT_MAX) { +    String *php_type_feature = Getattr(n, "feature:php:type"); +    php_type_flag = 0; +    if (php_type_feature != NULL) { +      if (Equal(php_type_feature, "1")) { +	php_type_flag = 1; +      } else if (!Equal(php_type_feature, "0")) { +	php_type_flag = -1; +      } +    } +    arginfo_id = Copy(Getattr(n, "sym:name")); +    has_director_node = (Getattr(n, "directorNode") != NULL); +  } + +  ~PHPTypes() { +    Delete(merged_types); +    Delete(byref); +  } + +  void adjust(int num_required_, bool php_constructor) { +    num_required = std::min(num_required, num_required_); +    if (php_constructor) { +      // Don't add a return type declaration for a PHP __construct method +      // (because there it has no return type as far as PHP is concerned). +      php_type_flag = 0; +    } +  } + +  String *get_arginfo_id() const { +    return arginfo_id; +  } + +  // key is 0 for return type, or >= 1 for parameters numbered from 1 +  List *process_phptype(Node *n, int key, const String_or_char *attribute_name); + +  // Merge entries from o_merge_list into merge_list, skipping any entries +  // already present. +  // +  // Both merge_list and o_merge_list should be in sorted order. +  static void merge_type_lists(List *merge_list, List *o_merge_list); + +  void merge_from(const PHPTypes* o); + +  void set_byref(int key) { +    if (!byref) { +      byref = NewList(); +    } +    while (Len(byref) <= key) { +      Append(byref, None); +    } +    // If any overload takes a particular parameter by reference then the +    // dispatch function also needs to take that parameter by reference so +    // we can just set unconditionally here. +    Setitem(byref, key, ""); // Just needs to be something != None. +  } + +  void emit_arginfo(DOH *item, String *key) { +    Setmark(item, 1); +    char *colon_ptr = Strchr(key, ':'); +    assert(colon_ptr); +    int colon = (int)(colon_ptr - Char(key)); +    if (colon > 0 && Strcmp(colon_ptr + 1, "__construct") != 0) { +      // See if there's a parent class which implements this method, and if so +      // emit its arginfo and then merge its PHPTypes into ours as we need to +      // be compatible with it (whether it is virtual or not). +      String *this_class = NewStringWithSize(Char(key), colon); +      String *parent = this_class; +      while ((parent = Getattr(php_parent_class, parent)) != NULL) { +	String *k = NewStringf("%s%s", parent, colon_ptr); +	DOH *item = Getattr(all_phptypes, k); +	if (item) { +	  PHPTypes *p = (PHPTypes*)Data(item); +	  if (!Getmark(item)) { +	    p->emit_arginfo(item, k); +	  } +	  merge_from(p); +	  Delete(k); +	  break; +	} +	Delete(k); +      } +      Delete(this_class); +    } + +    // We want to only emit each different arginfo once, as that reduces the +    // size of both the generated source code and the compiled extension +    // module.  The parameters at this level are just named arg1, arg2, etc +    // so the arginfo will be the same for any function with the same number +    // of parameters and (if present) PHP type declarations for parameters and +    // return type. +    // +    // We generate the arginfo we want (taking care to normalise, e.g. the +    // lists of types are unique and in sorted order), then use the +    // arginfo_used Hash to see if we've already generated it. +    String *out_phptype = NULL; +    String *out_phpclasses = NewStringEmpty(); + +    // We provide a simple way to generate PHP return type declarations +    // except for directed methods.  The point of directors is to allow +    // subclassing in the target language, and if the wrapped method has +    // a return type declaration then an overriding method in user code +    // needs to have a compatible declaration. +    // +    // The upshot of this is that enabling return type declarations for +    // existing bindings would break compatibility with user code written +    // for an older version.  For parameters however the situation is +    // different because if the parent class declares types for parameters +    // a subclass overriding the function will be compatible whether it +    // declares them or not. +    // +    // directorNode being present seems to indicate if this method or one +    // it inherits from is directed, which is what we care about here. +    // Using (!is_member_director(n)) would get it wrong for testcase +    // director_frob. +    if (php_type_flag && (php_type_flag > 0 || !has_director_node)) { +      if (!GetFlag(has_directed_descendent, key)) { +	out_phptype = get_phptype(0, out_phpclasses, Getattr(parent_class_method_return_type, key)); +      } +    } + +    // ### in arginfo_code will be replaced with the id once that is known. +    String *arginfo_code = NewStringEmpty(); +    if (out_phptype) { +      if (Len(out_phpclasses)) { +	Replace(out_phpclasses, "\\", "\\\\", DOH_REPLACE_ANY); +	Printf(arginfo_code, "ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(swig_arginfo_###, 0, %d, %s, %s)\n", num_required, out_phpclasses, out_phptype); +      } else { +	Printf(arginfo_code, "ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(swig_arginfo_###, 0, %d, %s)\n", num_required, out_phptype); +      } +    } else { +      Printf(arginfo_code, "ZEND_BEGIN_ARG_INFO_EX(swig_arginfo_###, 0, 0, %d)\n", num_required); +    } + +    int phptypes_size = size(); +    for (int param_count = 1; param_count < phptypes_size; ++param_count) { +      String *phpclasses = NewStringEmpty(); +      String *phptype = get_phptype(param_count, phpclasses); + +      int byref = get_byref(param_count); + +      // FIXME: Should we be doing byref for return value as well? + +      if (phptype) { +	if (Len(phpclasses)) { +	  // We need to double any backslashes (which are PHP namespace +	  // separators) in the PHP class names as they get turned into +	  // C strings by the ZEND_ARG_OBJ_TYPE_MASK macro. +	  Replace(phpclasses, "\\", "\\\\", DOH_REPLACE_ANY); +	  Printf(arginfo_code, " ZEND_ARG_OBJ_TYPE_MASK(%d,arg%d,%s,%s,NULL)\n", byref, param_count, phpclasses, phptype); +	} else { +	  Printf(arginfo_code, " ZEND_ARG_TYPE_MASK(%d,arg%d,%s,NULL)\n", byref, param_count, phptype); +	} +      } else { +	Printf(arginfo_code, " ZEND_ARG_INFO(%d,arg%d)\n", byref, param_count); +      } +    } +    Printf(arginfo_code, "ZEND_END_ARG_INFO()\n"); + +    String *arginfo_id_same = Getattr(arginfo_used, arginfo_code); +    if (arginfo_id_same) { +      Printf(s_arginfo, "#define swig_arginfo_%s swig_arginfo_%s\n", arginfo_id, arginfo_id_same); +    } else { +      // Not had this arginfo before. +      Setattr(arginfo_used, arginfo_code, arginfo_id); +      arginfo_code = Copy(arginfo_code); +      Replace(arginfo_code, "###", arginfo_id, DOH_REPLACE_FIRST); +      Append(s_arginfo, arginfo_code); +    } +    Delete(arginfo_code); +    arginfo_code = NULL; +  } +}; + +static PHPTypes *phptypes = NULL; + +class PHP : public Language { +public: +  PHP() { +    director_language = 1; +  } + +  /* ------------------------------------------------------------ +   * main() +   * ------------------------------------------------------------ */ + +  virtual void main(int argc, char *argv[]) { +    SWIG_library_directory("php"); + +    for (int i = 1; i < argc; i++) { +      if (strcmp(argv[i], "-prefix") == 0) { +	if (argv[i + 1]) { +	  prefix = NewString(argv[i + 1]); +	  Swig_mark_arg(i); +	  Swig_mark_arg(i + 1); +	  i++; +	} else { +	  Swig_arg_error(); +	} +      } else if ((strcmp(argv[i], "-noshadow") == 0)) { +	shadow = 0; +	Swig_mark_arg(i); +      } else if (strcmp(argv[i], "-help") == 0) { +	fputs(usage, stdout); +      } +    } + +    Preprocessor_define("SWIGPHP 1", 0); +    Preprocessor_define("SWIGPHP7 1", 0); +    SWIG_typemap_lang("php"); +    SWIG_config_file("php.swg"); +    allow_overloading(); +  } + +  /* ------------------------------------------------------------ +   * top() +   * ------------------------------------------------------------ */ + +  virtual int top(Node *n) { + +    String *filen; + +    /* Check if directors are enabled for this module. */ +    Node *mod = Getattr(n, "module"); +    if (mod) { +      Node *options = Getattr(mod, "options"); +      if (options && Getattr(options, "directors")) { +	allow_directors(); +      } +    } + +    /* Set comparison with null for ConstructorToFunction */ +    setSubclassInstanceCheck(NewString("Z_TYPE_P($arg) != IS_NULL")); + +    /* Initialize all of the output files */ +    String *outfile = Getattr(n, "outfile"); +    String *outfile_h = Getattr(n, "outfile_h"); + +    /* main output file */ +    f_begin = NewFile(outfile, "w", SWIG_output_files()); +    if (!f_begin) { +      FileErrorDisplay(outfile); +      Exit(EXIT_FAILURE); +    } +    f_runtime = NewStringEmpty(); + +    /* sections of the output file */ +    s_init = NewStringEmpty(); +    r_init = NewStringEmpty(); +    s_shutdown = NewStringEmpty(); +    r_shutdown = NewStringEmpty(); +    s_header = NewString("/* header section */\n"); +    s_wrappers = NewString("/* wrapper section */\n"); +    s_creation = NewStringEmpty(); +    /* subsections of the init section */ +    s_vdecl = NewString("/* vdecl subsection */\n"); +    s_cinit = NewString("  /* cinit subsection */\n"); +    s_oinit = NewString("  /* oinit subsection */\n"); +    pragma_phpinfo = NewStringEmpty(); +    f_directors_h = NewStringEmpty(); +    f_directors = NewStringEmpty(); + +    if (directorsEnabled()) { +      f_runtime_h = NewFile(outfile_h, "w", SWIG_output_files()); +      if (!f_runtime_h) { +	FileErrorDisplay(outfile_h); +	Exit(EXIT_FAILURE); +      } +    } + +    /* Register file targets with the SWIG file handler */ +    Swig_register_filebyname("begin", f_begin); +    Swig_register_filebyname("runtime", f_runtime); +    Swig_register_filebyname("init", s_init); +    Swig_register_filebyname("rinit", r_init); +    Swig_register_filebyname("shutdown", s_shutdown); +    Swig_register_filebyname("rshutdown", r_shutdown); +    Swig_register_filebyname("header", s_header); +    Swig_register_filebyname("wrapper", s_wrappers); +    Swig_register_filebyname("director", f_directors); +    Swig_register_filebyname("director_h", f_directors_h); + +    Swig_banner(f_begin); + +    Swig_obligatory_macros(f_runtime, "PHP"); + +    if (directorsEnabled()) { +      Printf(f_runtime, "#define SWIG_DIRECTORS\n"); +    } + +    // We need to include php.h before string.h gets included, at least with +    // PHP 8.2.  Otherwise string.h is included without _GNU_SOURCE being +    // included and memrchr() doesn't get declared, and then inline code in +    // the PHP headers defines _GNU_SOURCE, includes string.h (which is a +    // no op thanks to the include gaurds), then tries to use memrchr() and +    // fails. +    // +    // We also need to suppress -Wdeclaration-after-statement if enabled +    // since with PHP 8.2 zend_operators.h contains inline code which triggers +    // this warning and our testsuite uses with option and -Werror.  I don't +    // see a good way to only do this within our testsuite, but disabling +    // it globally like this shouldn't be problematic. +    Append(f_runtime, +	   "\n" +	   "#if defined __GNUC__ && !defined __cplusplus\n" +	   "# if __GNUC__ >= 4\n" +	   "#  pragma GCC diagnostic push\n" +	   "#  pragma GCC diagnostic ignored \"-Wdeclaration-after-statement\"\n" +	   "# endif\n" +	   "#endif\n" +	   "#include \"php.h\"\n" +	   "#if defined __GNUC__ && !defined __cplusplus\n" +	   "# if __GNUC__ >= 4\n" +	   "#  pragma GCC diagnostic pop\n" +	   "# endif\n" +	   "#endif\n\n"); + +    /* Set the module name */ +    module = Copy(Getattr(n, "name")); +    cap_module = NewStringf("%(upper)s", module); +    if (!prefix) +      prefix = NewStringEmpty(); + +    if (directorsEnabled()) { +      Swig_banner(f_directors_h); +      Printf(f_directors_h, "\n"); +      Printf(f_directors_h, "#ifndef SWIG_%s_WRAP_H_\n", cap_module); +      Printf(f_directors_h, "#define SWIG_%s_WRAP_H_\n\n", cap_module); + +      String *filename = Swig_file_filename(outfile_h); +      Printf(f_directors, "\n#include \"%s\"\n\n", filename); +      Delete(filename); +    } + +    /* sub-sections of the php file */ +    pragma_code = NewStringEmpty(); +    pragma_incl = NewStringEmpty(); +    pragma_version = NULL; + +    /* Initialize the rest of the module */ + +    /* start the header section */ +    Printf(s_header, "#define SWIG_name  \"%s\"\n", module); +    Printf(s_header, "#ifdef __cplusplus\n"); +    Printf(s_header, "extern \"C\" {\n"); +    Printf(s_header, "#endif\n"); +    Printf(s_header, "#include \"php_ini.h\"\n"); +    Printf(s_header, "#include \"ext/standard/info.h\"\n"); +    Printf(s_header, "#include \"php_%s.h\"\n", module); +    Printf(s_header, "#ifdef __cplusplus\n"); +    Printf(s_header, "}\n"); +    Printf(s_header, "#endif\n\n"); + +    if (directorsEnabled()) { +      // Insert director runtime +      Swig_insert_file("director_common.swg", s_header); +      Swig_insert_file("director.swg", s_header); +    } + +    /* Create the .h file too */ +    filen = NewStringEmpty(); +    Printv(filen, SWIG_output_directory(), "php_", module, ".h", NIL); +    f_h = NewFile(filen, "w", SWIG_output_files()); +    if (!f_h) { +      FileErrorDisplay(filen); +      Exit(EXIT_FAILURE); +    } + +    Swig_banner(f_h); + +    Printf(f_h, "\n"); +    Printf(f_h, "#ifndef PHP_%s_H\n", cap_module); +    Printf(f_h, "#define PHP_%s_H\n\n", cap_module); +    Printf(f_h, "extern zend_module_entry %s_module_entry;\n", module); +    Printf(f_h, "#define phpext_%s_ptr &%s_module_entry\n\n", module, module); +    Printf(f_h, "#ifdef PHP_WIN32\n"); +    Printf(f_h, "# define PHP_%s_API __declspec(dllexport)\n", cap_module); +    Printf(f_h, "#else\n"); +    Printf(f_h, "# define PHP_%s_API\n", cap_module); +    Printf(f_h, "#endif\n\n"); + +    /* start the arginfo section */ +    s_arginfo = NewString("/* arginfo subsection */\n"); +    arginfo_used = NewHash(); + +    /* start the function entry section */ +    s_entry = NewString("/* entry subsection */\n"); + +    /* holds all the per-class function entry sections */ +    all_cs_entry = NewString("/* class entry subsection */\n"); +    cs_entry = NULL; +    fake_cs_entry = NULL; + +    Printf(s_entry, "/* Every non-class user visible function must have an entry here */\n"); +    Printf(s_entry, "static const zend_function_entry module_%s_functions[] = {\n", module); + +    /* Emit all of the code */ +    Language::top(n); + +    /* Emit all the arginfo.  We sort the keys so the output order doesn't depend on +     * hashkey order. +     */ +    { +      List *sorted_keys = SortedKeys(all_phptypes, Strcmp); +      for (Iterator k = First(sorted_keys); k.item; k = Next(k)) { +	DOH *val = Getattr(all_phptypes, k.item); +	if (!Getmark(val)) { +	  PHPTypes *p = (PHPTypes*)Data(val); +	  p->emit_arginfo(val, k.item); +	} +      } +      Delete(sorted_keys); +    } + +    SwigPHP_emit_pointer_type_registrations(); +    Dump(s_creation, s_header); +    Delete(s_creation); +    s_creation = NULL; + +    /* start the init section */ +    { +      String *s_init_old = s_init; +      s_init = NewString("/* init section */\n"); +      Printv(s_init, "zend_module_entry ", module, "_module_entry = {\n", NIL); +      Printf(s_init, "    STANDARD_MODULE_HEADER,\n"); +      Printf(s_init, "    \"%s\",\n", module); +      Printf(s_init, "    module_%s_functions,\n", module); +      Printf(s_init, "    PHP_MINIT(%s),\n", module); +      if (Len(s_shutdown) > 0) { +	Printf(s_init, "    PHP_MSHUTDOWN(%s),\n", module); +      } else { +	Printf(s_init, "    NULL, /* No MSHUTDOWN code */\n"); +      } +      if (Len(r_init) > 0) { +	Printf(s_init, "    PHP_RINIT(%s),\n", module); +      } else { +	Printf(s_init, "    NULL, /* No RINIT code */\n"); +      } +      if (Len(r_shutdown) > 0) { +	Printf(s_init, "    PHP_RSHUTDOWN(%s),\n", module); +      } else { +	Printf(s_init, "    NULL, /* No RSHUTDOWN code */\n"); +      } +      if (Len(pragma_phpinfo) > 0) { +	Printf(s_init, "    PHP_MINFO(%s),\n", module); +      } else { +	Printf(s_init, "    NULL, /* No MINFO code */\n"); +      } +      if (Len(pragma_version) > 0) { +	Printf(s_init, "    \"%s\",\n", pragma_version); +      } else { +	Printf(s_init, "    NO_VERSION_YET,\n"); +      } +      Printf(s_init, "    STANDARD_MODULE_PROPERTIES\n"); +      Printf(s_init, "};\n\n"); + +      Printf(s_init, "#ifdef __cplusplus\n"); +      Printf(s_init, "extern \"C\" {\n"); +      Printf(s_init, "#endif\n"); +      // We want to write "SWIGEXPORT ZEND_GET_MODULE(%s)" but ZEND_GET_MODULE +      // in PHP7 has "extern "C" { ... }" around it so we can't do that. +      Printf(s_init, "SWIGEXPORT zend_module_entry *get_module(void) { return &%s_module_entry; }\n", module); +      Printf(s_init, "#ifdef __cplusplus\n"); +      Printf(s_init, "}\n"); +      Printf(s_init, "#endif\n\n"); + +      Printf(s_init, "#define SWIG_php_minit PHP_MINIT_FUNCTION(%s)\n\n", module); + +      Printv(s_init, s_init_old, NIL); +      Delete(s_init_old); +    } + +    /* We have to register the constants before they are (possibly) used +     * by the pointer typemaps. This all needs re-arranging really as +     * things are being called in the wrong order +     */ + +    Printf(s_oinit, "  /* end oinit subsection */\n"); +    Printf(s_init, "%s\n", s_oinit); + +    /* Constants generated during top call */ +    Printf(s_cinit, "  /* end cinit subsection */\n"); +    Printf(s_init, "%s\n", s_cinit); +    Clear(s_cinit); +    Delete(s_cinit); + +    Printf(s_init, "  return SUCCESS;\n"); +    Printf(s_init, "}\n\n"); + +    // Now do REQUEST init which holds any user specified %rinit, and also vinit +    if (Len(r_init) > 0) { +      Printf(f_h, "PHP_RINIT_FUNCTION(%s);\n", module); + +      Printf(s_init, "PHP_RINIT_FUNCTION(%s)\n{\n", module); +      Printv(s_init, +	     "/* rinit section */\n", +	     r_init, "\n", +	     NIL); + +      Printf(s_init, "  return SUCCESS;\n"); +      Printf(s_init, "}\n\n"); +    } + +    Printf(f_h, "PHP_MINIT_FUNCTION(%s);\n", module); + +    if (Len(s_shutdown) > 0) { +      Printf(f_h, "PHP_MSHUTDOWN_FUNCTION(%s);\n", module); + +      Printv(s_init, "PHP_MSHUTDOWN_FUNCTION(", module, ")\n" +		     "/* shutdown section */\n" +		     "{\n", +		     s_shutdown, +		     "  return SUCCESS;\n" +		     "}\n\n", NIL); +    } + +    if (Len(r_shutdown) > 0) { +      Printf(f_h, "PHP_RSHUTDOWN_FUNCTION(%s);\n", module); + +      Printf(s_init, "PHP_RSHUTDOWN_FUNCTION(%s)\n{\n", module); +      Printf(s_init, "/* rshutdown section */\n"); +      Printf(s_init, "%s\n", r_shutdown); +      Printf(s_init, "    return SUCCESS;\n"); +      Printf(s_init, "}\n\n"); +    } + +    if (Len(pragma_phpinfo) > 0) { +      Printf(f_h, "PHP_MINFO_FUNCTION(%s);\n", module); + +      Printf(s_init, "PHP_MINFO_FUNCTION(%s)\n{\n", module); +      Printf(s_init, "%s", pragma_phpinfo); +      Printf(s_init, "}\n"); +    } + +    Printf(s_init, "/* end init section */\n"); + +    Printf(f_h, "\n#endif /* PHP_%s_H */\n", cap_module); + +    Delete(f_h); + +    String *type_table = NewStringEmpty(); +    SwigType_emit_type_table(f_runtime, type_table); +    Printf(s_header, "%s", type_table); +    Delete(type_table); + +    /* Oh dear, more things being called in the wrong order. This whole +     * function really needs totally redoing. +     */ + +    if (directorsEnabled()) { +      Dump(f_directors_h, f_runtime_h); +      Printf(f_runtime_h, "\n"); +      Printf(f_runtime_h, "#endif\n"); +      Delete(f_runtime_h); +    } + +    Printf(s_header, "/* end header section */\n"); +    Printf(s_wrappers, "/* end wrapper section */\n"); +    Printf(s_vdecl, "/* end vdecl subsection */\n"); + +    Dump(f_runtime, f_begin); +    Printv(f_begin, s_header, NIL); +    if (directorsEnabled()) { +      Dump(f_directors, f_begin); +    } +    Printv(f_begin, s_vdecl, s_wrappers, NIL); +    Printv(f_begin, s_arginfo, "\n\n", all_cs_entry, "\n\n", s_entry, +	" ZEND_FE_END\n};\n\n", NIL); +    if (fake_cs_entry) { +      Printv(f_begin, fake_cs_entry, " ZEND_FE_END\n};\n\n", NIL); +      Delete(fake_cs_entry); +      fake_cs_entry = NULL; +    } +    Printv(f_begin, s_init, NIL); +    Delete(s_header); +    Delete(s_wrappers); +    Delete(s_init); +    Delete(s_vdecl); +    Delete(all_cs_entry); +    Delete(s_entry); +    Delete(s_arginfo); +    Delete(f_runtime); +    Delete(f_begin); +    Delete(arginfo_used); + +    if (Len(pragma_incl) > 0 || Len(pragma_code) > 0) { +      /* PHP module file */ +      String *php_filename = NewStringEmpty(); +      Printv(php_filename, SWIG_output_directory(), module, ".php", NIL); + +      File *f_phpcode = NewFile(php_filename, "w", SWIG_output_files()); +      if (!f_phpcode) { +	FileErrorDisplay(php_filename); +	Exit(EXIT_FAILURE); +      } + +      Printf(f_phpcode, "<?php\n\n"); + +      if (Len(pragma_incl) > 0) { +	Printv(f_phpcode, pragma_incl, "\n", NIL); +      } + +      if (Len(pragma_code) > 0) { +	Printv(f_phpcode, pragma_code, "\n", NIL); +      } + +      Delete(f_phpcode); +      Delete(php_filename); +    } + +    return SWIG_OK; +  } + +  /* Just need to append function names to function table to register with PHP. */ +  void create_command(String *cname, String *fname, Node *n, bool dispatch, String *modes = NULL) { +    // This is for the single main zend_function_entry record +    ParmList *l = Getattr(n, "parms"); +    if (cname && !Equal(Getattr(n, "storage"), "friend")) { +      Printf(f_h, "static PHP_METHOD(%s%s,%s);\n", prefix, cname, fname); +      if (wrapperType != staticmemberfn && +	  wrapperType != staticmembervar && +	  !Equal(fname, "__construct")) { +	// Skip the first entry in the parameter list which is the this pointer. +	if (l) l = Getattr(l, "tmap:in:next"); +	// FIXME: does this throw the phptype key value off? +      } +    } else { +      if (dispatch) { +	Printf(f_h, "static ZEND_NAMED_FUNCTION(%s);\n", fname); +      } else { +	Printf(f_h, "static PHP_FUNCTION(%s);\n", fname); +      } +    } + +    phptypes->adjust(emit_num_required(l), Equal(fname, "__construct") ? true : false); + +    String *arginfo_id = phptypes->get_arginfo_id(); +    String *s = cs_entry; +    if (!s) s = s_entry; +    if (cname && !Equal(Getattr(n, "storage"), "friend")) { +      Printf(all_cs_entry, " PHP_ME(%s%s,%s,swig_arginfo_%s,%s)\n", prefix, cname, fname, arginfo_id, modes); +    } else { +      if (dispatch) { +	if (wrap_nonclass_global) { +	  Printf(s, " ZEND_NAMED_FE(%(lower)s,%s,swig_arginfo_%s)\n", Getattr(n, "sym:name"), fname, arginfo_id); +	} + +	if (wrap_nonclass_fake_class) { +	  (void)fake_class_name(); +	  Printf(fake_cs_entry, " ZEND_NAMED_ME(%(lower)s,%s,swig_arginfo_%s,ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)\n", Getattr(n, "sym:name"), fname, arginfo_id); +	} +      } else { +	if (wrap_nonclass_global) { +	  Printf(s, " PHP_FE(%s,swig_arginfo_%s)\n", fname, arginfo_id); +	} + +	if (wrap_nonclass_fake_class) { +	  String *fake_class = fake_class_name(); +	  Printf(fake_cs_entry, " PHP_ME(%s,%s,swig_arginfo_%s,ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)\n", fake_class, fname, arginfo_id); +	} +      } +    } +  } + +  /* ------------------------------------------------------------ +   * dispatchFunction() +   * ------------------------------------------------------------ */ +  void dispatchFunction(Node *n, int constructor) { +    /* Last node in overloaded chain */ + +    int maxargs; +    String *tmp = NewStringEmpty(); +    String *dispatch = Swig_overload_dispatch(n, "%s(INTERNAL_FUNCTION_PARAM_PASSTHRU); return;", &maxargs); + +    /* Generate a dispatch wrapper for all overloaded functions */ + +    Wrapper *f = NewWrapper(); +    String *symname = Getattr(n, "sym:name"); +    String *wname = NULL; +    String *modes = NULL; +    bool constructorRenameOverload = false; + +    if (constructor) { +      if (!Equal(class_name, Getattr(n, "constructorHandler:sym:name"))) { +	// Renamed constructor - turn into static factory method +	constructorRenameOverload = true; +	wname = Copy(Getattr(n, "constructorHandler:sym:name")); +      } else { +	wname = NewString("__construct"); +      } +    } else if (class_name) { +      wname = Getattr(n, "wrapper:method:name"); +    } else { +      wname = Swig_name_wrapper(symname); +    } + +    if (constructor) { +      modes = NewString("ZEND_ACC_PUBLIC | ZEND_ACC_CTOR"); +      if (constructorRenameOverload) { +	Append(modes, " | ZEND_ACC_STATIC"); +      } +    } else if (wrapperType == staticmemberfn || Cmp(Getattr(n, "storage"), "static") == 0) { +      modes = NewString("ZEND_ACC_PUBLIC | ZEND_ACC_STATIC"); +    } else { +      modes = NewString("ZEND_ACC_PUBLIC"); +    } + +    create_command(class_name, wname, n, true, modes); + +    if (class_name && !Equal(Getattr(n, "storage"), "friend")) { +      Printv(f->def, "static PHP_METHOD(", prefix, class_name, ",", wname, ") {\n", NIL); +    } else { +      Printv(f->def, "static ZEND_NAMED_FUNCTION(", wname, ") {\n", NIL); +    } + +    Wrapper_add_local(f, "argc", "int argc"); + +    Printf(tmp, "zval argv[%d]", maxargs); +    Wrapper_add_local(f, "argv", tmp); + +    Printf(f->code, "argc = ZEND_NUM_ARGS();\n"); + +    Printf(f->code, "zend_get_parameters_array_ex(argc, argv);\n"); + +    Replaceall(dispatch, "$args", "self,args"); + +    Printv(f->code, dispatch, "\n", NIL); + +    Printf(f->code, "zend_throw_exception(zend_ce_type_error, \"No matching function for overloaded '%s'\", 0);\n", symname); +    Printv(f->code, "fail:\n", NIL); +    Printv(f->code, "return;\n", NIL); +    Printv(f->code, "}\n", NIL); +    Wrapper_print(f, s_wrappers); + +    DelWrapper(f); +    Delete(dispatch); +    Delete(tmp); +  } + +  /* ------------------------------------------------------------ +   * functionWrapper() +   * ------------------------------------------------------------ */ + +  /* Helper function to check if class is wrapped */ +  bool is_class_wrapped(String *className) { +    if (!className) +      return false; +    Node *n = symbolLookup(className); +    return n && Getattr(n, "classtype") != NULL; +  } + +  void generate_magic_property_methods(Node *class_node) { +    String *swig_base = base_class; +    if (Equal(swig_base, "Exception") || !is_class_wrapped(swig_base)) { +      swig_base = NULL; +    } + +    static bool generated_magic_arginfo = false; +    if (!generated_magic_arginfo) { +      // Create arginfo entries for __get, __set and __isset. +      Append(s_arginfo, +	     "ZEND_BEGIN_ARG_INFO_EX(swig_magic_arginfo_get, 0, 0, 1)\n" +	     " ZEND_ARG_TYPE_MASK(0,arg1,MAY_BE_STRING,NULL)\n" +	     "ZEND_END_ARG_INFO()\n"); +      Append(s_arginfo, +	     "ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(swig_magic_arginfo_set, 0, 1, MAY_BE_VOID)\n" +	     " ZEND_ARG_TYPE_MASK(0,arg1,MAY_BE_STRING,NULL)\n" +	     " ZEND_ARG_INFO(0,arg2)\n" +	     "ZEND_END_ARG_INFO()\n"); +      Append(s_arginfo, +	     "ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(swig_magic_arginfo_isset, 0, 1, MAY_BE_BOOL)\n" +	     " ZEND_ARG_TYPE_MASK(0,arg1,MAY_BE_STRING,NULL)\n" +	     "ZEND_END_ARG_INFO()\n"); +      generated_magic_arginfo = true; +    } + +    Wrapper *f = NewWrapper(); + +    Printf(f_h, "PHP_METHOD(%s%s,__set);\n", prefix, class_name); +    Printf(all_cs_entry, " PHP_ME(%s%s,__set,swig_magic_arginfo_set,ZEND_ACC_PUBLIC)\n", prefix, class_name); +    Printf(f->code, "PHP_METHOD(%s%s,__set) {\n", prefix, class_name); + +    Printf(f->code, "  swig_object_wrapper *arg = SWIG_Z_FETCH_OBJ_P(ZEND_THIS);\n"); +    Printf(f->code, "  zval args[2];\n zval tempZval;\n  zend_string *arg2 = 0;\n\n"); +    Printf(f->code, "  if(ZEND_NUM_ARGS() != 2 || zend_get_parameters_array_ex(2, args) != SUCCESS) {\n"); +    Printf(f->code, "\tWRONG_PARAM_COUNT;\n}\n\n"); +    Printf(f->code, "  if (!arg) {\n"); +    Printf(f->code, "    zend_throw_exception(zend_ce_type_error, \"this pointer is NULL\", 0);\n"); +    Printf(f->code, "    return;\n"); +    Printf(f->code, "  }\n"); +    Printf(f->code, "  arg2 = Z_STR(args[0]);\n\n"); + +    Printf(f->code, "if (!arg2) {\n  RETVAL_NULL();\n}\n"); +    if (magic_set) { +      Append(f->code, magic_set); +    } +    Printf(f->code, "\nelse if (strcmp(ZSTR_VAL(arg2),\"thisown\") == 0) {\n"); +    Printf(f->code, "arg->newobject = zval_get_long(&args[1]);\n"); +    if (Swig_directorclass(class_node)) { +      Printv(f->code, "if (arg->newobject == 0) {\n", +		      "  Swig::Director *director = SWIG_DIRECTOR_CAST((", Getattr(class_node, "classtype"), "*)(arg->ptr));\n", +		      "  if (director) director->swig_disown();\n", +		      "}\n", NIL); +    } +    if (swig_base) { +      Printf(f->code, "} else {\nPHP_MN(%s%s___set)(INTERNAL_FUNCTION_PARAM_PASSTHRU);\n", prefix, swig_base); +    } else if (Getattr(class_node, "feature:php:allowdynamicproperties")) { +      Printf(f->code, "} else {\nadd_property_zval_ex(ZEND_THIS, ZSTR_VAL(arg2), ZSTR_LEN(arg2), &args[1]);\n"); +    } +    Printf(f->code, "}\n"); + +    Printf(f->code, "fail:\n"); +    Printf(f->code, "return;\n"); +    Printf(f->code, "}\n\n\n"); + + +    Printf(f_h, "PHP_METHOD(%s%s,__get);\n", prefix, class_name); +    Printf(all_cs_entry, " PHP_ME(%s%s,__get,swig_magic_arginfo_get,ZEND_ACC_PUBLIC)\n", prefix, class_name); +    Printf(f->code, "PHP_METHOD(%s%s,__get) {\n",prefix, class_name); + +    Printf(f->code, "  swig_object_wrapper *arg = SWIG_Z_FETCH_OBJ_P(ZEND_THIS);\n"); +    Printf(f->code, "  zval args[1];\n zval tempZval;\n  zend_string *arg2 = 0;\n\n"); +    Printf(f->code, "  if(ZEND_NUM_ARGS() != 1 || zend_get_parameters_array_ex(1, args) != SUCCESS) {\n"); +    Printf(f->code, "\tWRONG_PARAM_COUNT;\n}\n\n"); +    Printf(f->code, "  if (!arg) {\n"); +    Printf(f->code, "    zend_throw_exception(zend_ce_type_error, \"this pointer is NULL\", 0);\n"); +    Printf(f->code, "    return;\n"); +    Printf(f->code, "  }\n"); +    Printf(f->code, "  arg2 = Z_STR(args[0]);\n\n"); + +    Printf(f->code, "if (!arg2) {\n  RETVAL_NULL();\n}\n"); +    if (magic_get) { +      Append(f->code, magic_get); +    } +    Printf(f->code, "\nelse if (strcmp(ZSTR_VAL(arg2),\"thisown\") == 0) {\n"); +    Printf(f->code, "if(arg->newobject) {\nRETVAL_LONG(1);\n}\nelse {\nRETVAL_LONG(0);\n}\n}\n\n"); +    Printf(f->code, "else {\n"); +    if (swig_base) { +      Printf(f->code, "PHP_MN(%s%s___get)(INTERNAL_FUNCTION_PARAM_PASSTHRU);\n}\n", prefix, swig_base); +    } else { +      // __get is only called if the property isn't set on the zend_object. +      Printf(f->code, "RETVAL_NULL();\n}\n"); +    } + +    Printf(f->code, "fail:\n"); +    Printf(f->code, "return;\n"); +    Printf(f->code, "}\n\n\n"); + + +    Printf(f_h, "PHP_METHOD(%s%s,__isset);\n", prefix, class_name); +    Printf(all_cs_entry, " PHP_ME(%s%s,__isset,swig_magic_arginfo_isset,ZEND_ACC_PUBLIC)\n", prefix, class_name); +    Printf(f->code, "PHP_METHOD(%s%s,__isset) {\n",prefix, class_name); + +    Printf(f->code, "  swig_object_wrapper *arg = SWIG_Z_FETCH_OBJ_P(ZEND_THIS);\n"); +    Printf(f->code, "  zval args[1];\n  zend_string *arg2 = 0;\n\n"); +    Printf(f->code, "  if(ZEND_NUM_ARGS() != 1 || zend_get_parameters_array_ex(1, args) != SUCCESS) {\n"); +    Printf(f->code, "\tWRONG_PARAM_COUNT;\n}\n\n"); +    Printf(f->code, "  if(!arg) {\n"); +    Printf(f->code, "    zend_throw_exception(zend_ce_type_error, \"this pointer is NULL\", 0);\n"); +    Printf(f->code, "    return;\n"); +    Printf(f->code, "  }\n"); +    Printf(f->code, "  arg2 = Z_STR(args[0]);\n\n"); + +    Printf(f->code, "if (!arg2) {\n  RETVAL_FALSE;\n}\n"); +    Printf(f->code, "\nelse if (strcmp(ZSTR_VAL(arg2),\"thisown\") == 0) {\n"); +    Printf(f->code, "RETVAL_TRUE;\n}\n\n"); +    if (magic_isset) { +      Append(f->code, magic_isset); +    } +    Printf(f->code, "else {\n"); +    if (swig_base) { +      Printf(f->code, "PHP_MN(%s%s___isset)(INTERNAL_FUNCTION_PARAM_PASSTHRU);\n}\n", prefix, swig_base); +    } else { +      // __isset is only called if the property isn't set on the zend_object. +      Printf(f->code, "RETVAL_FALSE;\n}\n"); +    } + +    Printf(f->code, "fail:\n"); +    Printf(f->code, "return;\n"); +    Printf(f->code, "}\n\n\n"); + +    Wrapper_print(f, s_wrappers); +    DelWrapper(f); +    f = NULL; + +    Delete(magic_set); +    Delete(magic_get); +    Delete(magic_isset); +    magic_set = NULL; +    magic_get = NULL; +    magic_isset = NULL; +  } + +  String *getAccessMode(String *access) { +    if (Cmp(access, "protected") == 0) { +      return NewString("ZEND_ACC_PROTECTED"); +    } else if (Cmp(access, "private") == 0) { +      return NewString("ZEND_ACC_PRIVATE"); +    } +    return NewString("ZEND_ACC_PUBLIC"); +  } + +  bool is_setter_method(Node *n) { +    const char *p = GetChar(n, "sym:name"); +    if (strlen(p) > 4) { +      p += strlen(p) - 4; +      if (strcmp(p, "_set") == 0) { +	return true; +      } +    } +    return false; +  } + +  bool is_getter_method(Node *n) { +    const char *p = GetChar(n, "sym:name"); +    if (strlen(p) > 4) { +      p += strlen(p) - 4; +      if (strcmp(p, "_get") == 0) { +	return true; +      } +    } +    return false; +  } + +  virtual int functionWrapper(Node *n) { +    if (wrapperType == directordisown) { +      // Handled via __set magic method - no explicit wrapper method wanted. +      return SWIG_OK; +    } +    String *name = GetChar(n, "name"); +    String *iname = GetChar(n, "sym:name"); +    SwigType *d = Getattr(n, "type"); +    ParmList *l = Getattr(n, "parms"); +    String *nodeType = Getattr(n, "nodeType"); +    int newobject = GetFlag(n, "feature:new"); +    int constructor = (Cmp(nodeType, "constructor") == 0); + +    Parm *p; +    int i; +    int numopt; +    String *tm; +    Wrapper *f; + +    String *wname = NewStringEmpty(); +    String *overloadwname = NULL; +    int overloaded = 0; +    String *modes = NULL; +    bool static_setter = false; +    bool static_getter = false; + +    modes = getAccessMode(Getattr(n, "access")); + +    if (constructor) { +      Append(modes, " | ZEND_ACC_CTOR"); +    } +    if (wrapperType == staticmemberfn || Cmp(Getattr(n, "storage"), "static") == 0) { +      Append(modes, " | ZEND_ACC_STATIC"); +    } +    if (GetFlag(n, "abstract") && Swig_directorclass(Swig_methodclass(n)) && !is_member_director(n)) +      Append(modes, " | ZEND_ACC_ABSTRACT"); + +    if (Getattr(n, "sym:overloaded")) { +      overloaded = 1; +      overloadwname = NewString(Swig_name_wrapper(iname)); +      Printf(overloadwname, "%s", Getattr(n, "sym:overname")); +    } else { +      if (!addSymbol(iname, n)) +	return SWIG_ERROR; +    } + +    if (constructor) { +      if (!Equal(class_name, Getattr(n, "constructorHandler:sym:name"))) { +	// Renamed constructor - turn into static factory method +	wname = Copy(Getattr(n, "constructorHandler:sym:name")); +      } else { +	wname = NewString("__construct"); +      } +    } else if (wrapperType == membervar) { +      wname = Copy(Getattr(n, "membervariableHandler:sym:name")); +      if (is_setter_method(n)) { +	Append(wname, "_set"); +      } else if (is_getter_method(n)) { +	Append(wname, "_get"); +      } +    } else if (wrapperType == memberfn) { +      wname = Getattr(n, "memberfunctionHandler:sym:name"); +    } else if (wrapperType == staticmembervar) { +      // Shape::nshapes -> nshapes +      wname = Getattr(n, "staticmembervariableHandler:sym:name"); + +      /* We get called twice for getter and setter methods. But to maintain +	 compatibility, Shape::nshapes() is being used for both setter and +	 getter methods. So using static_setter and static_getter variables +	 to generate half of the code each time. +       */ +      static_setter = is_setter_method(n); + +      if (is_getter_method(n)) { +	// This is to overcome types that can't be set and hence no setter. +	if (!Equal(Getattr(n, "feature:immutable"), "1")) +	  static_getter = true; +      } +    } else if (wrapperType == staticmemberfn) { +      wname = Getattr(n, "staticmemberfunctionHandler:sym:name"); +    } else { +      if (class_name) { +	if (Cmp(Getattr(n, "storage"), "friend") == 0 && Cmp(Getattr(n, "view"), "globalfunctionHandler") == 0) { +	  wname = iname; +	} else { +	  wname = Getattr(n, "destructorHandler:sym:name"); +	} +      } else { +	wname = iname; +      } +    } + +    if (wrapperType == destructor) { +      // We don't explicitly wrap the destructor for PHP - Zend manages the +      // reference counting, and the user can just do `$obj = null;' or similar +      // to remove a reference to an object. +      Setattr(n, "wrap:name", wname); +      (void)emit_action(n); +      return SWIG_OK; +    } + +    if (!static_getter) { +      // Create or find existing PHPTypes. +      phptypes = NULL; + +      String *key; +      if (class_name && !Equal(Getattr(n, "storage"), "friend")) { +	key = NewStringf("%s:%s", class_name, wname); +      } else { +	key = NewStringf(":%s", wname); +      } + +      PHPTypes *p = (PHPTypes*)GetVoid(all_phptypes, key); +      if (p) { +	// We already have an entry so use it. +	phptypes = p; +	Delete(key); +      } else { +	phptypes = new PHPTypes(n); +	SetVoid(all_phptypes, key, phptypes); +      } +    } + +    f = NewWrapper(); + +    if (static_getter) { +      Printf(f->def, "{\n"); +    } + +    String *outarg = NewStringEmpty(); +    String *cleanup = NewStringEmpty(); + +    if (!overloaded) { +      if (!static_getter) { +	if (class_name && !Equal(Getattr(n, "storage"), "friend")) { +	  Printv(f->def, "static PHP_METHOD(", prefix, class_name, ",", wname, ") {\n", NIL); +	} else { +	  if (wrap_nonclass_global) { +	    Printv(f->def, "static PHP_METHOD(", fake_class_name(), ",", wname, ") {\n", +			   "  PHP_FN(", wname, ")(INTERNAL_FUNCTION_PARAM_PASSTHRU);\n", +			   "}\n\n", NIL); +	  } + +	  if (wrap_nonclass_fake_class) { +	    Printv(f->def, "static PHP_FUNCTION(", wname, ") {\n", NIL); +	  } +	} +      } +    } else { +      Printv(f->def, "static ZEND_NAMED_FUNCTION(", overloadwname, ") {\n", NIL); +    } + +    emit_parameter_variables(l, f); +    /* Attach standard typemaps */ + +    emit_attach_parmmaps(l, f); + +    if (wrapperType == memberfn || wrapperType == membervar) { +      // Assign "this" to arg1 and remove first entry from ParmList l. +      Printf(f->code, "arg1 = (%s)SWIG_Z_FETCH_OBJ_P(ZEND_THIS)->ptr;\n", SwigType_lstr(Getattr(l, "type"), "")); +      l = nextSibling(l); +    } + +    // wrap:parms is used by overload resolution. +    Setattr(n, "wrap:parms", l); + +    int num_arguments = emit_num_arguments(l); +    int num_required = emit_num_required(l); +    numopt = num_arguments - num_required; + +    if (num_arguments > 0) { +      String *args = NewStringEmpty(); +      Printf(args, "zval args[%d]", num_arguments); +      Wrapper_add_local(f, "args", args); +      Delete(args); +      args = NULL; +    } +    if (wrapperType == directorconstructor) { +      Wrapper_add_local(f, "arg0", "zval *arg0 = ZEND_THIS"); +    } + +    // This generated code may be called: +    // 1) as an object method, or +    // 2) as a class-method/function (without a "this_ptr") +    // Option (1) has "this_ptr" for "this", option (2) needs it as +    // first parameter + +    // NOTE: possible we ignore this_ptr as a param for native constructor + +    if (numopt > 0) {		// membervariable wrappers do not have optional args +      Wrapper_add_local(f, "arg_count", "int arg_count"); +      Printf(f->code, "arg_count = ZEND_NUM_ARGS();\n"); +      Printf(f->code, "if(arg_count<%d || arg_count>%d ||\n", num_required, num_arguments); +      Printf(f->code, "   zend_get_parameters_array_ex(arg_count,args)!=SUCCESS)\n"); +      Printf(f->code, "\tWRONG_PARAM_COUNT;\n\n"); +    } else if (static_setter || static_getter) { +      if (num_arguments == 0) { +	Printf(f->code, "if(ZEND_NUM_ARGS() == 0) {\n"); +      } else { +	Printf(f->code, "if(ZEND_NUM_ARGS() == %d && zend_get_parameters_array_ex(%d, args) == SUCCESS) {\n", num_arguments, num_arguments); +      } +    } else { +      if (num_arguments == 0) { +	Printf(f->code, "if(ZEND_NUM_ARGS() != 0) {\n"); +      } else { +	Printf(f->code, "if(ZEND_NUM_ARGS() != %d || zend_get_parameters_array_ex(%d, args) != SUCCESS) {\n", num_arguments, num_arguments); +      } +      Printf(f->code, "WRONG_PARAM_COUNT;\n}\n\n"); +    } + +    /* Now convert from PHP to C variables */ +    // At this point, argcount if used is the number of deliberately passed args +    // not including this_ptr even if it is used. +    // It means error messages may be out by argbase with error +    // reports.  We can either take argbase into account when raising +    // errors, or find a better way of dealing with _thisptr. +    // I would like, if objects are wrapped, to assume _thisptr is always +    // _this and not the first argument. +    // This may mean looking at Language::memberfunctionHandler + +    for (i = 0, p = l; i < num_arguments; i++) { +      /* Skip ignored arguments */ +      while (checkAttribute(p, "tmap:in:numinputs", "0")) { +	p = Getattr(p, "tmap:in:next"); +      } + +      /* Check if optional */ +      if (i >= num_required) { +	Printf(f->code, "\tif(arg_count > %d) {\n", i); +      } + +      tm = Getattr(p, "tmap:in"); +      if (!tm) { +	SwigType *pt = Getattr(p, "type"); +	Swig_warning(WARN_TYPEMAP_IN_UNDEF, input_file, line_number, "Unable to use type %s as a function argument.\n", SwigType_str(pt, 0)); +	p = nextSibling(p); +	continue; +      } + +      phptypes->process_phptype(p, i + 1, "tmap:in:phptype"); +      if (GetFlag(p, "tmap:in:byref")) phptypes->set_byref(i + 1); + +      String *source = NewStringf("args[%d]", i); +      Replaceall(tm, "$input", source); +      Setattr(p, "emit:input", source); +      Printf(f->code, "%s\n", tm); +      if (i == 0 && Getattr(p, "self")) { +	Printf(f->code, "\tif(!arg1) {\n"); +	Printf(f->code, "\t  zend_throw_exception(zend_ce_type_error, \"this pointer is NULL\", 0);\n"); +	Printf(f->code, "\t  return;\n"); +	Printf(f->code, "\t}\n"); +      } + +      if (i >= num_required) { +	Printf(f->code, "}\n"); +      } + +      p = Getattr(p, "tmap:in:next"); + +      Delete(source); +    } + +    if (is_member_director(n)) { +      Wrapper_add_local(f, "director", "Swig::Director *director = 0"); +      Append(f->code, "director = SWIG_DIRECTOR_CAST(arg1);\n"); +      Wrapper_add_local(f, "upcall", "bool upcall = false"); +      Printf(f->code, "upcall = (director && (director->swig_get_self()==Z_OBJ_P(ZEND_THIS)));\n"); +    } + +    Swig_director_emit_dynamic_cast(n, f); + +    /* Insert constraint checking code */ +    for (p = l; p;) { +      if ((tm = Getattr(p, "tmap:check"))) { +	Printv(f->code, tm, "\n", NIL); +	p = Getattr(p, "tmap:check:next"); +      } else { +	p = nextSibling(p); +      } +    } + +    /* Insert cleanup code */ +    for (i = 0, p = l; p; i++) { +      if ((tm = Getattr(p, "tmap:freearg"))) { +	Printv(cleanup, tm, "\n", NIL); +	p = Getattr(p, "tmap:freearg:next"); +      } else { +	p = nextSibling(p); +      } +    } + +    /* Insert argument output code */ +    for (i = 0, p = l; p; i++) { +      if ((tm = Getattr(p, "tmap:argout")) && Len(tm)) { +	Replaceall(tm, "$result", "return_value"); +	Replaceall(tm, "$arg", Getattr(p, "emit:input")); +	Replaceall(tm, "$input", Getattr(p, "emit:input")); +	Printv(outarg, tm, "\n", NIL); +	p = Getattr(p, "tmap:argout:next"); +      } else { +	p = nextSibling(p); +      } +    } + +    if (!overloaded) { +      Setattr(n, "wrap:name", wname); +    } else { +      Setattr(n, "wrap:name", overloadwname); +    } +    Setattr(n, "wrapper:method:name", wname); + +    bool php_constructor = (constructor && Cmp(class_name, Getattr(n, "constructorHandler:sym:name")) == 0); + +    /* emit function call */ +    String *actioncode = emit_action(n); + +    if ((tm = Swig_typemap_lookup_out("out", n, Swig_cresult_name(), f, actioncode))) { +      Replaceall(tm, "$input", Swig_cresult_name()); +      Replaceall(tm, "$result", php_constructor ? "ZEND_THIS" : "return_value"); +      Replaceall(tm, "$owner", newobject ? "1" : "0"); +      Printf(f->code, "%s\n", tm); +    } else { +      Swig_warning(WARN_TYPEMAP_OUT_UNDEF, input_file, line_number, "Unable to use return type %s in function %s.\n", SwigType_str(d, 0), name); +    } +    emit_return_variable(n, d, f); + +    List *return_types = phptypes->process_phptype(n, 0, "tmap:out:phptype"); + +    if (class_name && !Equal(Getattr(n, "storage"), "friend")) { +      if (is_member_director(n)) { +	String *parent = class_name; +	while ((parent = Getattr(php_parent_class, parent)) != NULL) { +	  // Mark this method name as having no return type declaration for all +	  // classes we're derived from. +	  SetFlag(has_directed_descendent, NewStringf("%s:%s", parent, wname)); +	} +      } else if (return_types) { +	String *parent = class_name; +	while ((parent = Getattr(php_parent_class, parent)) != NULL) { +	  String *key = NewStringf("%s:%s", parent, wname); +	  // The parent class method needs to have a superset of the possible +	  // return types of methods with the same name in subclasses. +	  List *v = Getattr(parent_class_method_return_type, key); +	  if (!v) { +	    // New entry. +	    Setattr(parent_class_method_return_type, key, Copy(return_types)); +	  } else { +	    // Update existing entry. +	    PHPTypes::merge_type_lists(v, return_types); +	  } +	} +      } +    } + +    if (outarg) { +      Printv(f->code, outarg, NIL); +    } + +    if (static_setter && cleanup) { +      Printv(f->code, cleanup, NIL); +    } + +    /* Look to see if there is any newfree cleanup code */ +    if (GetFlag(n, "feature:new")) { +      if ((tm = Swig_typemap_lookup("newfree", n, Swig_cresult_name(), 0))) { +	Printf(f->code, "%s\n", tm); +	Delete(tm); +      } +    } + +    /* See if there is any return cleanup code */ +    if ((tm = Swig_typemap_lookup("ret", n, Swig_cresult_name(), 0))) { +      Printf(f->code, "%s\n", tm); +      Delete(tm); +    } + +    if (static_getter) { +      Printf(f->code, "}\n"); +    } + +    if (static_setter || static_getter) { +      Printf(f->code, "}\n"); +    } + +    if (!static_setter) { +      Printf(f->code, "fail:\n"); +      Printv(f->code, cleanup, NIL); +      Printf(f->code, "return;\n"); +      Printf(f->code, "}\n"); +    } + +    Replaceall(f->code, "$cleanup", cleanup); +    Replaceall(f->code, "$symname", iname); + +    Wrapper_print(f, s_wrappers); +    DelWrapper(f); +    f = NULL; + +    if (overloaded) { +      if (!Getattr(n, "sym:nextSibling")) { +	dispatchFunction(n, constructor); +      } +    } else { +      if (!static_setter) { +	create_command(class_name, wname, n, false, modes); +      } +    } + +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * globalvariableHandler() +   * ------------------------------------------------------------ */ + +  /* PHP doesn't support intercepting reads and writes to global variables +   * (nor static property reads and writes so we can't wrap them as static +   * properties on a dummy class) so just let SWIG do its default thing and +   * wrap them as name_get() and name_set(). +   */ +  //virtual int globalvariableHandler(Node *n) { +  //} + +  /* ------------------------------------------------------------ +   * constantWrapper() +   * ------------------------------------------------------------ */ + +  virtual int constantWrapper(Node *n) { +    String *name = GetChar(n, "name"); +    String *iname = GetChar(n, "sym:name"); +    SwigType *type = Getattr(n, "type"); +    String *rawval = Getattr(n, "rawval"); +    String *value = rawval ? rawval : Getattr(n, "value"); +    String *tm; + +    if (!addSymbol(iname, n)) +      return SWIG_ERROR; + +    SwigType_remember(type); + +    String *wrapping_member_constant = Getattr(n, "memberconstantHandler:sym:name"); +    if (!wrapping_member_constant) { +      { +	tm = Swig_typemap_lookup("consttab", n, name, 0); +	Replaceall(tm, "$value", value); +	if (Getattr(n, "tmap:consttab:rinit")) { +	  Printf(r_init, "%s\n", tm); +	} else { +	  Printf(s_cinit, "%s\n", tm); +	} +      } + +      { +	tm = Swig_typemap_lookup("classconsttab", n, name, 0); + +	Replaceall(tm, "$class", fake_class_name()); +	Replaceall(tm, "$const_name", iname); +	Replaceall(tm, "$value", value); +	if (Getattr(n, "tmap:classconsttab:rinit")) { +	  Printf(r_init, "%s\n", tm); +	} else { +	  Printf(s_cinit, "%s\n", tm); +	} +      } +    } else { +      tm = Swig_typemap_lookup("classconsttab", n, name, 0); +      Replaceall(tm, "$class", class_name); +      Replaceall(tm, "$const_name", wrapping_member_constant); +      Replaceall(tm, "$value", value); +      if (Getattr(n, "tmap:classconsttab:rinit")) { +	Printf(r_init, "%s\n", tm); +      } else { +	Printf(s_cinit, "%s\n", tm); +      } +    } + +    wrapperType = standard; +    return SWIG_OK; +  } + +  /* +   * PHP::pragma() +   * +   * Pragma directive. +   * +   * %pragma(php) code="String"         # Includes a string in the .php file +   * %pragma(php) include="file.php"    # Includes a file in the .php file +   */ + +  virtual int pragmaDirective(Node *n) { +    if (!ImportMode) { +      String *lang = Getattr(n, "lang"); +      String *type = Getattr(n, "name"); +      String *value = Getattr(n, "value"); + +      if (Strcmp(lang, "php") == 0) { +	if (Strcmp(type, "code") == 0) { +	  if (value) { +	    Printf(pragma_code, "%s\n", value); +	  } +	} else if (Strcmp(type, "include") == 0) { +	  if (value) { +	    Printf(pragma_incl, "include '%s';\n", value); +	  } +	} else if (Strcmp(type, "phpinfo") == 0) { +	  if (value) { +	    Printf(pragma_phpinfo, "%s\n", value); +	  } +	} else if (Strcmp(type, "version") == 0) { +	  if (value) { +	    pragma_version = value; +	  } +	} else { +	  Swig_warning(WARN_PHP_UNKNOWN_PRAGMA, input_file, line_number, "Unrecognized pragma <%s>.\n", type); +	} +      } +    } +    return Language::pragmaDirective(n); +  } + +  /* ------------------------------------------------------------ +   * classDeclaration() +   * ------------------------------------------------------------ */ + +  virtual int classDeclaration(Node *n) { +    return Language::classDeclaration(n); +  } + +  /* ------------------------------------------------------------ +   * classHandler() +   * ------------------------------------------------------------ */ + +  virtual int classHandler(Node *n) { +    String *symname = Getattr(n, "sym:name"); + +    class_name = symname; +    base_class = NULL; +    destructor_action = NULL; + +    Printf(all_cs_entry, "static const zend_function_entry class_%s_functions[] = {\n", class_name); + +    // namespace code to introduce namespaces into wrapper classes. +    //if (nameSpace != NULL) +      //Printf(s_oinit, "INIT_CLASS_ENTRY(internal_ce, \"%s\\\\%s\", class_%s_functions);\n", nameSpace, class_name, class_name); +    //else +    Printf(s_oinit, "  INIT_CLASS_ENTRY(internal_ce, \"%s%s\", class_%s_functions);\n", prefix, class_name, class_name); + +    if (shadow) { +      char *rename = GetChar(n, "sym:name"); + +      if (!addSymbol(rename, n)) +	return SWIG_ERROR; + +      /* Deal with inheritance */ +      List *baselist = Getattr(n, "bases"); +      if (baselist) { +	Iterator base = First(baselist); +	while (base.item) { +	  if (!GetFlag(base.item, "feature:ignore")) { +	    if (!base_class) { +	      base_class = Getattr(base.item, "sym:name"); +	    } else { +	      /* Warn about multiple inheritance for additional base class(es) */ +	      String *proxyclassname = SwigType_str(Getattr(n, "classtypeobj"), 0); +	      String *baseclassname = SwigType_str(Getattr(base.item, "name"), 0); +	      Swig_warning(WARN_PHP_MULTIPLE_INHERITANCE, input_file, line_number, +			   "Warning for %s, base %s ignored. Multiple inheritance is not supported in PHP.\n", proxyclassname, baseclassname); +	    } +	  } +	  base = Next(base); +	} +      } +    } + +    if (GetFlag(n, "feature:exceptionclass") && Getattr(n, "feature:except")) { +      /* PHP requires thrown objects to be instances of or derived from +       * Exception, so that really needs to take priority over any +       * explicit base class. +       */ +      if (base_class) { +	String *proxyclassname = SwigType_str(Getattr(n, "classtypeobj"), 0); +	Swig_warning(WARN_PHP_MULTIPLE_INHERITANCE, input_file, line_number, +		     "Warning for %s, base %s ignored. Multiple inheritance is not supported in PHP.\n", proxyclassname, base_class); +      } +      base_class = NewString("Exception"); +    } + +    if (!base_class) { +      Printf(s_oinit, "  SWIG_Php_ce_%s = zend_register_internal_class(&internal_ce);\n", class_name); +    } else if (Equal(base_class, "Exception")) { +      Printf(s_oinit, "  SWIG_Php_ce_%s = zend_register_internal_class_ex(&internal_ce, zend_ce_exception);\n", class_name); +    } else if (is_class_wrapped(base_class)) { +      Printf(s_oinit, "  SWIG_Php_ce_%s = zend_register_internal_class_ex(&internal_ce, SWIG_Php_ce_%s);\n", class_name, base_class); +      Setattr(php_parent_class, class_name, base_class); +    } else { +      Printf(s_oinit, "  {\n"); +      Printf(s_oinit, "    swig_type_info *type_info = SWIG_MangledTypeQueryModule(swig_module.next, &swig_module, \"_p_%s\");\n", base_class); +      Printf(s_oinit, "    SWIG_Php_ce_%s = zend_register_internal_class_ex(&internal_ce, (zend_class_entry*)(type_info ? type_info->clientdata : NULL));\n", class_name); +      Printf(s_oinit, "  }\n"); +    } + +    if (Getattr(n, "abstracts") && !GetFlag(n, "feature:notabstract")) { +      Printf(s_oinit, "  SWIG_Php_ce_%s->ce_flags |= ZEND_ACC_EXPLICIT_ABSTRACT_CLASS;\n", class_name); +    } +    if (Getattr(n, "feature:php:allowdynamicproperties")) { +      Append(s_oinit, "#ifdef ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES\n"); +      Printf(s_oinit, "  SWIG_Php_ce_%s->ce_flags |= ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES;\n", class_name); +      Append(s_oinit, "#endif\n"); +    } else { +      Append(s_oinit, "#ifdef ZEND_ACC_NO_DYNAMIC_PROPERTIES\n"); +      Printf(s_oinit, "  SWIG_Php_ce_%s->ce_flags |= ZEND_ACC_NO_DYNAMIC_PROPERTIES;\n", class_name); +      Append(s_oinit, "#endif\n"); +    } +    String *swig_wrapped = swig_wrapped_interface_ce(); +    Printv(s_oinit, "  zend_do_implement_interface(SWIG_Php_ce_", class_name, ", &", swig_wrapped, ");\n", NIL); + +    { +      Node *node = NewHash(); +      Setattr(node, "type", Getattr(n, "name")); +      Setfile(node, Getfile(n)); +      Setline(node, Getline(n)); +      String *interfaces = Swig_typemap_lookup("phpinterfaces", node, "", 0); +      Replaceall(interfaces, " ", ""); +      if (interfaces && Len(interfaces) > 0) { +	// It seems we need to wait until RINIT time to look up class entries +	// for interfaces by name.  The downside is that this then happens for +	// every request. +	// +	// Most pre-defined interfaces are accessible via zend_class_entry* +	// variables declared in the PHP C API - these we can use at MINIT +	// time, so we special case them.  This will also be a little faster +	// than looking up by name. +	Printv(s_header, +	       "#ifdef __cplusplus\n", +	       "extern \"C\" {\n", +	       "#endif\n", +	       NIL); + +	String *r_init_prefix = NewStringEmpty(); + +	List *interface_list = Split(interfaces, ',', -1); +	int num_interfaces = Len(interface_list); +	for (int i = 0; i < num_interfaces; ++i) { +	  String *interface = Getitem(interface_list, i); +	  // We generate conditional code in both minit and rinit - then we or the user +	  // just need to define SWIG_PHP_INTERFACE_xxx_CE (and optionally +	  // SWIG_PHP_INTERFACE_xxx_HEADER) to handle interface `xxx` at minit-time. +	  Printv(s_header, +		 "#ifdef SWIG_PHP_INTERFACE_", interface, "_HEADER\n", +		 "# include SWIG_PHP_INTERFACE_", interface, "_HEADER\n", +		 "#endif\n", +		 NIL); +	  Printv(s_oinit, +		 "#ifdef SWIG_PHP_INTERFACE_", interface, "_CE\n", +		 "  zend_do_implement_interface(SWIG_Php_ce_", class_name, ", SWIG_PHP_INTERFACE_", interface, "_CE);\n", +		 "#endif\n", +		 NIL); +	  Printv(r_init_prefix, +		 "#ifndef SWIG_PHP_INTERFACE_", interface, "_CE\n", +		 "  {\n", +		 "    zend_class_entry *swig_interface_ce = zend_lookup_class(zend_string_init(\"", interface, "\", sizeof(\"", interface, "\") - 1, 0));\n", +		 "    if (swig_interface_ce)\n", +		 "      zend_do_implement_interface(SWIG_Php_ce_", class_name, ", swig_interface_ce);\n", +                 "    else\n", +                 "      zend_throw_exception(zend_ce_error, \"Interface \\\"", interface, "\\\" not found\", 0);\n", +		 "  }\n", +		 "#endif\n", +		 NIL); +	} + +	// Handle interfaces at the start of rinit so that they're added +	// before any potential constant objects, etc which might be created +	// later in rinit. +	Insert(r_init, 0, r_init_prefix); +	Delete(r_init_prefix); + +	Printv(s_header, +	       "#ifdef __cplusplus\n", +	       "}\n", +	       "#endif\n", +	       NIL); +      } +      Delete(interfaces); +    } + +    Language::classHandler(n); + +    static bool emitted_base_object_handlers = false; +    if (!emitted_base_object_handlers) { +      Printf(s_creation, "static zend_object_handlers Swig_Php_base_object_handlers;\n\n"); + +      // Set up a base zend_object_handlers structure which we can use as-is +      // for classes without a destructor, and copy as the basis for other +      // classes. +      Printf(s_oinit, "  Swig_Php_base_object_handlers = *zend_get_std_object_handlers();\n"); +      Printf(s_oinit, "  Swig_Php_base_object_handlers.offset = XtOffsetOf(swig_object_wrapper, std);\n"); +      Printf(s_oinit, "  Swig_Php_base_object_handlers.clone_obj = NULL;\n"); +      emitted_base_object_handlers = true; +    } + +    Printf(s_creation, "static zend_class_entry *SWIG_Php_ce_%s;\n\n", class_name); + +    if (Getattr(n, "has_destructor")) { +      if (destructor_action ? Equal(destructor_action, "free((char *) arg1);") : !CPlusPlus) { +	// We can use a single function if the destructor action calls free() +	// (either explicitly or as the default in C-mode) since free() doesn't +	// care about the object's type.  We currently only check for the exact +	// code that Swig_cdestructor_call() emits. +	static bool emitted_common_cdestructor = false; +	if (!emitted_common_cdestructor) { +	  Printf(s_creation, "static zend_object_handlers Swig_Php_common_c_object_handlers;\n\n"); +	  Printf(s_creation, "static void SWIG_Php_common_c_free_obj(zend_object *object) {free(SWIG_Php_free_obj(object));}\n\n"); +	  Printf(s_creation, "static zend_object *SWIG_Php_common_c_create_object(zend_class_entry *ce) {return SWIG_Php_do_create_object(ce, &Swig_Php_common_c_object_handlers);}\n"); + +	  Printf(s_oinit, "  Swig_Php_common_c_object_handlers = Swig_Php_base_object_handlers;\n"); +	  Printf(s_oinit, "  Swig_Php_common_c_object_handlers.free_obj = SWIG_Php_common_c_free_obj;\n"); + +	  emitted_common_cdestructor = true; +	} + +	Printf(s_oinit, "  SWIG_Php_ce_%s->create_object = SWIG_Php_common_c_create_object;\n", class_name); +      } else { +	Printf(s_creation, "static zend_object_handlers %s_object_handlers;\n", class_name); +	Printf(s_creation, "static zend_object *SWIG_Php_create_object_%s(zend_class_entry *ce) {return SWIG_Php_do_create_object(ce, &%s_object_handlers);}\n", class_name, class_name); + +	Printf(s_creation, "static void SWIG_Php_free_obj_%s(zend_object *object) {",class_name); +	String *type = Getattr(n, "classtype"); +	// Special case handling the delete call generated by +	// Swig_cppdestructor_call() and generate simpler code. +	if (destructor_action && !Equal(destructor_action, "delete arg1;")) { +	  Printv(s_creation, "\n" +		 "  ", type, " *arg1 = (" , type, " *)SWIG_Php_free_obj(object);\n" +		 "  if (arg1) {\n" +		 "    ", destructor_action, "\n" +		 "  }\n", NIL); +	} else { +	  Printf(s_creation, "delete (%s *)SWIG_Php_free_obj(object);", type); +	} +	Printf(s_creation, "}\n\n"); + +	Printf(s_oinit, "  SWIG_Php_ce_%s->create_object = SWIG_Php_create_object_%s;\n", class_name, class_name); +	Printf(s_oinit, "  %s_object_handlers = Swig_Php_base_object_handlers;\n", class_name); +	Printf(s_oinit, "  %s_object_handlers.free_obj = SWIG_Php_free_obj_%s;\n", class_name, class_name); +      } +    } else { +      static bool emitted_destructorless_create_object = false; +      if (!emitted_destructorless_create_object) { +	emitted_destructorless_create_object = true; +	Printf(s_creation, "static zend_object *SWIG_Php_create_object(zend_class_entry *ce) {return SWIG_Php_do_create_object(ce, &Swig_Php_base_object_handlers);}\n", class_name); +      } + +      Printf(s_oinit, "  SWIG_Php_ce_%s->create_object = SWIG_Php_create_object;\n", class_name); +    } + +    // If not defined we aren't wrapping any functions which use this type as a +    // parameter or return value, in which case we don't need the clientdata +    // set. +    Printf(s_oinit, "#ifdef SWIGTYPE_p%s\n", SwigType_manglestr(Getattr(n, "classtypeobj"))); +    Printf(s_oinit, "  SWIG_TypeClientData(SWIGTYPE_p%s,SWIG_Php_ce_%s);\n", SwigType_manglestr(Getattr(n, "classtypeobj")), class_name); +    Printf(s_oinit, "#endif\n"); +    Printf(s_oinit, "\n"); + +    generate_magic_property_methods(n); +    Printf(all_cs_entry, " ZEND_FE_END\n};\n\n"); + +    class_name = NULL; +    base_class = NULL; +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * memberfunctionHandler() +   * ------------------------------------------------------------ */ + +  virtual int memberfunctionHandler(Node *n) { +    wrapperType = memberfn; +    Language::memberfunctionHandler(n); +    wrapperType = standard; + +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * membervariableHandler() +   * ------------------------------------------------------------ */ + +  virtual int membervariableHandler(Node *n) { +    if (magic_set == NULL) { +      magic_set = NewStringEmpty(); +      magic_get = NewStringEmpty(); +      magic_isset = NewStringEmpty(); +    } + +    String *v_name = GetChar(n, "name"); + +    Printf(magic_set, "\nelse if (strcmp(ZSTR_VAL(arg2),\"%s\") == 0) {\n", v_name); +    Printf(magic_set, "ZVAL_STRING(&tempZval, \"%s_set\");\n", v_name); +    Printf(magic_set, "call_user_function(EG(function_table),ZEND_THIS,&tempZval,return_value,1,&args[1]);\n}\n"); + +    Printf(magic_get, "\nelse if (strcmp(ZSTR_VAL(arg2),\"%s\") == 0) {\n", v_name); +    Printf(magic_get, "ZVAL_STRING(&tempZval, \"%s_get\");\n", v_name); +    Printf(magic_get, "call_user_function(EG(function_table),ZEND_THIS,&tempZval,return_value,0,NULL);\n}\n"); + +    Printf(magic_isset, "\nelse if (strcmp(ZSTR_VAL(arg2),\"%s\") == 0) {\n", v_name); +    Printf(magic_isset, "RETVAL_TRUE;\n}\n"); + +    wrapperType = membervar; +    Language::membervariableHandler(n); +    wrapperType = standard; + +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * staticmembervariableHandler() +   * ------------------------------------------------------------ */ + +  virtual int staticmembervariableHandler(Node *n) { +    wrapperType = staticmembervar; +    Language::staticmembervariableHandler(n); +    wrapperType = standard; + +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * staticmemberfunctionHandler() +   * ------------------------------------------------------------ */ + +  virtual int staticmemberfunctionHandler(Node *n) { +    wrapperType = staticmemberfn; +    Language::staticmemberfunctionHandler(n); +    wrapperType = standard; + +    return SWIG_OK; +  } + +  int abstractConstructorHandler(Node *) { +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * constructorHandler() +   * ------------------------------------------------------------ */ + +  virtual int constructorHandler(Node *n) { +    if (Swig_directorclass(n)) { +      String *ctype = GetChar(Swig_methodclass(n), "classtype"); +      String *sname = GetChar(Swig_methodclass(n), "sym:name"); +      String *args = NewStringEmpty(); +      ParmList *p = Getattr(n, "parms"); +      int i; + +      for (i = 0; p; p = nextSibling(p), i++) { +	if (i) { +	  Printf(args, ", "); +	} +	if (Strcmp(GetChar(p, "type"), SwigType_str(GetChar(p, "type"), 0))) { +	  SwigType *t = Getattr(p, "type"); +	  Printf(args, "%s", SwigType_rcaststr(t, 0)); +	  if (SwigType_isreference(t)) { +	    Append(args, "*"); +	  } +	} +	Printf(args, "arg%d", i+1); +      } + +      /* director ctor code is specific for each class */ +      Delete(director_ctor_code); +      director_ctor_code = NewStringEmpty(); +      director_prot_ctor_code = NewStringEmpty(); +      Printf(director_ctor_code, "if (Z_OBJCE_P(arg0) == SWIG_Php_ce_%s) { /* not subclassed */\n", class_name); +      Printf(director_prot_ctor_code, "if (Z_OBJCE_P(arg0) == SWIG_Php_ce_%s) { /* not subclassed */\n", class_name); +      Printf(director_ctor_code, "  %s = new %s(%s);\n", Swig_cresult_name(), ctype, args); +      Printf(director_prot_ctor_code, +	     "  zend_throw_exception(zend_ce_type_error, \"accessing abstract class or protected constructor\", 0);\n" +	     "  return;\n"); +      if (i) { +	Insert(args, 0, ", "); +      } +      Printf(director_ctor_code, "} else {\n  %s = (%s *)new SwigDirector_%s(arg0%s);\n}\n", Swig_cresult_name(), ctype, sname, args); +      Printf(director_prot_ctor_code, "} else {\n  %s = (%s *)new SwigDirector_%s(arg0%s);\n}\n", Swig_cresult_name(), ctype, sname, args); +      Delete(args); + +      wrapperType = directorconstructor; +    } else { +      wrapperType = constructor; +    } +    Language::constructorHandler(n); +    wrapperType = standard; + +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * destructorHandler() +   * ------------------------------------------------------------ */ +  virtual int destructorHandler(Node *n) { +    wrapperType = destructor; +    Language::destructorHandler(n); +    destructor_action = Getattr(n, "wrap:action"); +    wrapperType = standard; +    return SWIG_OK; +  } + +  int classDirectorInit(Node *n) { +    String *declaration = Swig_director_declaration(n); +    Printf(f_directors_h, "%s\n", declaration); +    Printf(f_directors_h, "public:\n"); +    Delete(declaration); +    return Language::classDirectorInit(n); +  } + +  int classDirectorEnd(Node *n) { +    Printf(f_directors_h, "};\n"); +    return Language::classDirectorEnd(n); +  } + +  int classDirectorConstructor(Node *n) { +    Node *parent = Getattr(n, "parentNode"); +    String *decl = Getattr(n, "decl"); +    String *supername = Swig_class_name(parent); +    String *classname = NewStringEmpty(); +    Printf(classname, "SwigDirector_%s", supername); + +    /* insert self parameter */ +    Parm *p; +    ParmList *superparms = Getattr(n, "parms"); +    ParmList *parms = CopyParmList(superparms); +    String *type = NewString("zval"); +    SwigType_add_pointer(type); +    p = NewParm(type, NewString("self"), n); +    set_nextSibling(p, parms); +    parms = p; + +    if (!Getattr(n, "defaultargs")) { +      // There should always be a "self" parameter first. +      assert(ParmList_len(parms) > 0); + +      /* constructor */ +      { +	Wrapper *w = NewWrapper(); +	String *call; +	String *basetype = Getattr(parent, "classtype"); + +	String *target = Swig_method_decl(0, decl, classname, parms, 0); +	call = Swig_csuperclass_call(0, basetype, superparms); +	Printf(w->def, "%s::%s: %s, Swig::Director(self) {", classname, target, call); +	Append(w->def, "}"); +	Delete(target); +	Wrapper_print(w, f_directors); +	Delete(call); +	DelWrapper(w); +      } + +      /* constructor header */ +      { +	String *target = Swig_method_decl(0, decl, classname, parms, 1); +	Printf(f_directors_h, "    %s;\n", target); +	Delete(target); +      } +    } +    return Language::classDirectorConstructor(n); +  } + +  int classDirectorMethod(Node *n, Node *parent, String *super) { +    int is_void = 0; +    int is_pointer = 0; +    String *decl = Getattr(n, "decl"); +    String *returntype = Getattr(n, "type"); +    String *name = Getattr(n, "name"); +    String *classname = Getattr(parent, "sym:name"); +    String *c_classname = Getattr(parent, "name"); +    String *symname = Getattr(n, "sym:name"); +    String *declaration = NewStringEmpty(); +    ParmList *l = Getattr(n, "parms"); +    Wrapper *w = NewWrapper(); +    String *tm; +    String *wrap_args = NewStringEmpty(); +    String *value = Getattr(n, "value"); +    String *storage = Getattr(n, "storage"); +    bool pure_virtual = false; +    int status = SWIG_OK; +    int idx; +    bool ignored_method = GetFlag(n, "feature:ignore") ? true : false; + +    if (Cmp(storage, "virtual") == 0) { +      if (Cmp(value, "0") == 0) { +	pure_virtual = true; +      } +    } + +    /* determine if the method returns a pointer */ +    is_pointer = SwigType_ispointer_return(decl); +    is_void = (Cmp(returntype, "void") == 0 && !is_pointer); + +    /* virtual method definition */ +    String *target; +    String *pclassname = NewStringf("SwigDirector_%s", classname); +    String *qualified_name = NewStringf("%s::%s", pclassname, name); +    SwigType *rtype = Getattr(n, "conversion_operator") ? 0 : Getattr(n, "classDirectorMethods:type"); +    target = Swig_method_decl(rtype, decl, qualified_name, l, 0); +    Printf(w->def, "%s", target); +    Delete(qualified_name); +    Delete(target); +    /* header declaration */ +    target = Swig_method_decl(rtype, decl, name, l, 1); +    Printf(declaration, "    virtual %s", target); +    Delete(target); + +    // Get any exception classes in the throws typemap +    if (Getattr(n, "noexcept")) { +      Append(w->def, " noexcept"); +      Append(declaration, " noexcept"); +    } +    ParmList *throw_parm_list = 0; + +    if ((throw_parm_list = Getattr(n, "throws")) || Getattr(n, "throw")) { +      Parm *p; +      int gencomma = 0; + +      Append(w->def, " throw("); +      Append(declaration, " throw("); + +      if (throw_parm_list) +	Swig_typemap_attach_parms("throws", throw_parm_list, 0); +      for (p = throw_parm_list; p; p = nextSibling(p)) { +	if (Getattr(p, "tmap:throws")) { +	  if (gencomma++) { +	    Append(w->def, ", "); +	    Append(declaration, ", "); +	  } +	  String *str = SwigType_str(Getattr(p, "type"), 0); +	  Append(w->def, str); +	  Append(declaration, str); +	  Delete(str); +	} +      } + +      Append(w->def, ")"); +      Append(declaration, ")"); +    } + +    Append(w->def, " {"); +    Append(declaration, ";\n"); + +    /* declare method return value +     * if the return value is a reference or const reference, a specialized typemap must +     * handle it, including declaration of c_result ($result). +     */ +    if (!is_void && (!ignored_method || pure_virtual)) { +      if (!SwigType_isclass(returntype)) { +	if (!(SwigType_ispointer(returntype) || SwigType_isreference(returntype))) { +	  String *construct_result = NewStringf("= SwigValueInit< %s >()", SwigType_lstr(returntype, 0)); +	  Wrapper_add_localv(w, "c_result", SwigType_lstr(returntype, "c_result"), construct_result, NIL); +	  Delete(construct_result); +	} else { +	  Wrapper_add_localv(w, "c_result", SwigType_lstr(returntype, "c_result"), "= 0", NIL); +	} +      } else { +	String *cres = SwigType_lstr(returntype, "c_result"); +	Printf(w->code, "%s;\n", cres); +	Delete(cres); +      } +    } + +    if (ignored_method) { +      if (!pure_virtual) { +	if (!is_void) +	  Printf(w->code, "return "); +	String *super_call = Swig_method_call(super, l); +	Printf(w->code, "%s;\n", super_call); +	Delete(super_call); +      } else { +	Printf(w->code, "Swig::DirectorPureVirtualException::raise(\"Attempted to invoke pure virtual method %s::%s\");\n", SwigType_namestr(c_classname), +	       SwigType_namestr(name)); +      } +    } else { +      /* attach typemaps to arguments (C/C++ -> PHP) */ +      Swig_director_parms_fixup(l); + +      /* remove the wrapper 'w' since it was producing spurious temps */ +      Swig_typemap_attach_parms("in", l, 0); +      Swig_typemap_attach_parms("directorin", l, w); +      Swig_typemap_attach_parms("directorargout", l, w); + +      Parm *p; + +      /* build argument list and type conversion string */ +      idx = 0; +      p = l; +      while (p) { +	if (checkAttribute(p, "tmap:in:numinputs", "0")) { +	  p = Getattr(p, "tmap:in:next"); +	  continue; +	} + +	String *pname = Getattr(p, "name"); +	String *ptype = Getattr(p, "type"); + +	if ((tm = Getattr(p, "tmap:directorin")) != 0) { +	  String *parse = Getattr(p, "tmap:directorin:parse"); +	  if (!parse) { +	    String *input = NewStringf("&args[%d]", idx++); +	    Setattr(p, "emit:directorinput", input); +	    Replaceall(tm, "$input", input); +	    Delete(input); +	    Replaceall(tm, "$owner", "0"); +	    Printv(wrap_args, tm, "\n", NIL); +	  } else { +	    Setattr(p, "emit:directorinput", pname); +	    Replaceall(tm, "$input", pname); +	    Replaceall(tm, "$owner", "0"); +	    if (Len(tm) == 0) +	      Append(tm, pname); +	  } +	  p = Getattr(p, "tmap:directorin:next"); +	  continue; +	} else if (Cmp(ptype, "void")) { +	  Swig_warning(WARN_TYPEMAP_DIRECTORIN_UNDEF, input_file, line_number, +	      "Unable to use type %s as a function argument in director method %s::%s (skipping method).\n", SwigType_str(ptype, 0), +	      SwigType_namestr(c_classname), SwigType_namestr(name)); +	  status = SWIG_NOWRAP; +	  break; +	} +	p = nextSibling(p); +      } + +      if (!idx) { +	Printf(w->code, "zval *args = NULL;\n"); +      } else { +	Printf(w->code, "zval args[%d];\n", idx); +      } +      // typemap_directorout testcase requires that 0 can be assigned to the +      // variable named after the result of Swig_cresult_name(), so that can't +      // be a zval - make it a pointer to one instead. +      Printf(w->code, "zval swig_zval_result;\n"); +      Printf(w->code, "zval * SWIGUNUSED %s = &swig_zval_result;\n", Swig_cresult_name()); + +      /* wrap complex arguments to zvals */ +      Append(w->code, wrap_args); + +      const char *funcname = GetChar(n, "sym:name"); +      Append(w->code, "{\n"); +      Append(w->code, "#if PHP_MAJOR_VERSION < 8\n"); +      Printf(w->code, "zval swig_funcname;\n"); +      Printf(w->code, "ZVAL_STRINGL(&swig_funcname, \"%s\", %d);\n", funcname, strlen(funcname)); +      Printf(w->code, "call_user_function(EG(function_table), &swig_self, &swig_funcname, &swig_zval_result, %d, args);\n", idx); +      Append(w->code, "#else\n"); +      Printf(w->code, "zend_string *swig_funcname = zend_string_init(\"%s\", %d, 0);\n", funcname, strlen(funcname)); +      Append(w->code, "zend_function *swig_zend_func = zend_std_get_method(&Z_OBJ(swig_self), swig_funcname, NULL);\n"); +      Append(w->code, "zend_string_release(swig_funcname);\n"); +      Printf(w->code, "if (swig_zend_func) zend_call_known_instance_method(swig_zend_func, Z_OBJ(swig_self), &swig_zval_result, %d, args);\n", idx); +      Append(w->code, "#endif\n"); + +      /* exception handling */ +      tm = Swig_typemap_lookup("director:except", n, Swig_cresult_name(), 0); +      if (!tm) { +	tm = Getattr(n, "feature:director:except"); +	if (tm) +	  tm = Copy(tm); +      } +      if (!tm || Len(tm) == 0 || Equal(tm, "1")) { +	// Skip marshalling the return value as there isn't one. +	tm = NewString("if ($error) SWIG_fail;"); +      } + +      Replaceall(tm, "$error", "EG(exception)"); +      Printv(w->code, Str(tm), "\n}\n{\n", NIL); +      Delete(tm); + +      /* marshal return value from PHP to C/C++ type */ + +      String *cleanup = NewStringEmpty(); +      String *outarg = NewStringEmpty(); + +      idx = 0; + +      /* marshal return value */ +      if (!is_void) { +	tm = Swig_typemap_lookup("directorout", n, Swig_cresult_name(), w); +	if (tm != 0) { +	  Replaceall(tm, "$input", Swig_cresult_name()); +	  char temp[24]; +	  sprintf(temp, "%d", idx); +	  Replaceall(tm, "$argnum", temp); + +	  /* TODO check this */ +	  if (Getattr(n, "wrap:disown")) { +	    Replaceall(tm, "$disown", "SWIG_POINTER_DISOWN"); +	  } else { +	    Replaceall(tm, "$disown", "0"); +	  } +	  Replaceall(tm, "$result", "c_result"); +	  Printv(w->code, tm, "\n", NIL); +	  Delete(tm); +	} else { +	  Swig_warning(WARN_TYPEMAP_DIRECTOROUT_UNDEF, input_file, line_number, +		       "Unable to use return type %s in director method %s::%s (skipping method).\n", SwigType_str(returntype, 0), +		       SwigType_namestr(c_classname), SwigType_namestr(name)); +	  status = SWIG_ERROR; +	} +      } + +      /* marshal outputs */ +      for (p = l; p;) { +	if ((tm = Getattr(p, "tmap:directorargout")) != 0) { +	  Replaceall(tm, "$result", Swig_cresult_name()); +	  Replaceall(tm, "$input", Getattr(p, "emit:directorinput")); +	  Printv(w->code, tm, "\n", NIL); +	  p = Getattr(p, "tmap:directorargout:next"); +	} else { +	  p = nextSibling(p); +	} +      } + +      Append(w->code, "}\n"); + +      Delete(cleanup); +      Delete(outarg); +    } + +    Append(w->code, "fail: ;\n"); +    if (!is_void) { +      if (!(ignored_method && !pure_virtual)) { +	String *rettype = SwigType_str(returntype, 0); +	if (!SwigType_isreference(returntype)) { +	  Printf(w->code, "return (%s) c_result;\n", rettype); +	} else { +	  Printf(w->code, "return (%s) *c_result;\n", rettype); +	} +	Delete(rettype); +      } +    } +    Append(w->code, "}\n"); + +    // We expose protected methods via an extra public inline method which makes a straight call to the wrapped class' method +    String *inline_extra_method = NewStringEmpty(); +    if (dirprot_mode() && !is_public(n) && !pure_virtual) { +      Printv(inline_extra_method, declaration, NIL); +      String *extra_method_name = NewStringf("%sSwigPublic", name); +      Replaceall(inline_extra_method, name, extra_method_name); +      Replaceall(inline_extra_method, ";\n", " {\n      "); +      if (!is_void) +	Printf(inline_extra_method, "return "); +      String *methodcall = Swig_method_call(super, l); +      Printv(inline_extra_method, methodcall, ";\n    }\n", NIL); +      Delete(methodcall); +      Delete(extra_method_name); +    } + +    /* emit the director method */ +    if (status == SWIG_OK) { +      if (!Getattr(n, "defaultargs")) { +	Replaceall(w->code, "$symname", symname); +	Wrapper_print(w, f_directors); +	Printv(f_directors_h, declaration, NIL); +	Printv(f_directors_h, inline_extra_method, NIL); +      } +    } + +    /* clean up */ +    Delete(wrap_args); +    Delete(pclassname); +    DelWrapper(w); +    return status; +  } + +  int classDirectorDisown(Node *n) { +    wrapperType = directordisown; +    int result = Language::classDirectorDisown(n); +    wrapperType = standard; +    return result; +  } +};				/* class PHP */ + +static PHP *maininstance = 0; + +List *PHPTypes::process_phptype(Node *n, int key, const String_or_char *attribute_name) { + +  while (Len(merged_types) <= key) { +    Append(merged_types, NewList()); +  } + +  String *phptype = Getattr(n, attribute_name); +  if (!phptype || Len(phptype) == 0) { +    // There's no type declaration, so any merged version has no type declaration. +    // +    // Use a DOH None object as a marker to indicate there's no type +    // declaration for this parameter/return value (you can't store NULL as a +    // value in a DOH List). +    Setitem(merged_types, key, None); +    return NULL; +  } + +  DOH *merge_list = Getitem(merged_types, key); +  if (merge_list == None) return NULL; + +  List *types = Split(phptype, '|', -1); +  String *first_type = Getitem(types, 0); +  if (Char(first_type)[0] == '?') { +    if (Len(types) > 1) { +      Printf(stderr, "warning: Invalid phptype: '%s' (can't use ? and | together)\n", phptype); +    } +    // Treat `?foo` just like `foo|null`. +    Append(types, "null"); +    Setitem(types, 0, NewString(Char(first_type) + 1)); +  } + +  SortList(types, NULL); +  String *prev = NULL; +  for (Iterator i = First(types); i.item; i = Next(i)) { +    if (prev && Equal(prev, i.item)) { +      Printf(stderr, "warning: Invalid phptype: '%s' (duplicate entry for '%s')\n", phptype, i.item); +      continue; +    } + +    if (key > 0 && Equal(i.item, "void")) { +      // Reject void for parameter type. +      Printf(stderr, "warning: Invalid phptype: '%s' ('%s' can't be used as a parameter phptype)\n", phptype, i.item); +      continue; +    } + +    if (Equal(i.item, "SWIGTYPE")) { +      String *type = Getattr(n, "type"); +      Node *class_node = maininstance->classLookup(type); +      if (class_node) { +	// FIXME: Prefix classname with a backslash to prevent collisions +	// with built-in types?  Or are non of those valid anyway and so will +	// have been renamed at this point? +	Append(merge_list, Getattr(class_node, "sym:name")); +      } else { +	// SWIG wraps a pointer to a non-object type as an object in a PHP +	// class named based on the SWIG-mangled C/C++ type. +	// +	// FIXME: We should check this is actually a known pointer to +	// non-object type so we complain about `phptype="SWIGTYPE"` being +	// used for PHP types like `int` or `string` (currently this only +	// fails at runtime and the error isn't very helpful).  We could +	// check the condition +	// +	//   raw_pointer_types && Getattr(raw_pointer_types, SwigType_manglestr(type)) +	// +	// except that raw_pointer_types may not have been fully filled in when +	// we are called. +	Append(merge_list, NewStringf("SWIG\\%s", SwigType_manglestr(type))); +      } +    } else { +      Append(merge_list, i.item); +    } +    prev = i.item; +  } +  SortList(merge_list, NULL); +  return merge_list; +} + +void PHPTypes::merge_type_lists(List *merge_list, List *o_merge_list) { +  int i = 0, j = 0; +  while (j < Len(o_merge_list)) { +    String *candidate = Getitem(o_merge_list, j); +    while (i < Len(merge_list)) { +      int cmp = Cmp(Getitem(merge_list, i), candidate); +      if (cmp == 0) +	goto handled; +      if (cmp > 0) +	break; +      ++i; +    } +    Insert(merge_list, i, candidate); +    ++i; +handled: +    ++j; +  } +} + +void PHPTypes::merge_from(const PHPTypes* o) { +  num_required = std::min(num_required, o->num_required); + +  if (o->byref) { +    if (byref == NULL) { +      byref = Copy(o->byref); +    } else { +      int len = std::min(Len(byref), Len(o->byref)); +      // Start at 1 because we only want to merge parameter types, and key 0 is +      // the return type. +      for (int key = 1; key < len; ++key) { +	if (Getitem(byref, key) == None && +	    Getitem(o->byref, key) != None) { +	  Setitem(byref, key, ""); +	} +      } +      for (int key = len; key < Len(o->byref); ++key) { +	Append(byref, Getitem(o->byref, key)); +      } +    } +  } + +  int len = std::min(Len(merged_types), Len(o->merged_types)); +  for (int key = 0; key < len; ++key) { +    DOH *merge_list = Getitem(merged_types, key); +    // None trumps anything else in the merge. +    if (merge_list == None) continue; +    DOH *o_merge_list = Getitem(o->merged_types, key); +    if (o_merge_list == None) { +      Setitem(merged_types, key, None); +      continue; +    } +    merge_type_lists(merge_list, o_merge_list); +  } +  // Copy over any additional entries. +  for (int key = len; key < Len(o->merged_types); ++key) { +    Append(merged_types, Copy(Getitem(o->merged_types, key))); +  } +} + +// Collect non-class pointer types from the type table so we can set up PHP +// classes for them later. +// +// NOTE: it's a function NOT A PHP::METHOD +extern "C" { +static void typetrace(const SwigType *ty, String *mangled, String *clientdata) { +  if (maininstance->classLookup(ty) == NULL) { +    // a non-class pointer +    if (!raw_pointer_types) { +      raw_pointer_types = NewHash(); +    } +    Setattr(raw_pointer_types, mangled, mangled); +  } +  if (r_prevtracefunc) +    (*r_prevtracefunc) (ty, mangled, clientdata); +} +} + +/* ----------------------------------------------------------------------------- + * new_swig_php()    - Instantiate module + * ----------------------------------------------------------------------------- */ + +static Language *new_swig_php() { +  maininstance = new PHP; +  if (!r_prevtracefunc) { +    r_prevtracefunc = SwigType_remember_trace(typetrace); +  } else { +    Printf(stderr, "php Typetrace vector already saved!\n"); +    assert(0); +  } +  return maininstance; +} + +extern "C" Language *swig_php(void) { +  return new_swig_php(); +} diff --git a/contrib/tools/swig/Source/Modules/python.cxx b/contrib/tools/swig/Source/Modules/python.cxx new file mode 100644 index 00000000000..63f0c1650d9 --- /dev/null +++ b/contrib/tools/swig/Source/Modules/python.cxx @@ -0,0 +1,5768 @@ +/* ----------------------------------------------------------------------------- + * This file is part of SWIG, which is licensed as a whole under version 3 + * (or any later version) of the GNU General Public License. Some additional + * terms also apply to certain portions of SWIG. The full details of the SWIG + * license and copyrights can be found in the LICENSE and COPYRIGHT files + * included with the SWIG source code as distributed by the SWIG developers + * and at https://www.swig.org/legal.html. + * + * python.cxx + * + * Python language module for SWIG. + * ----------------------------------------------------------------------------- */ + +#include "swigmod.h" +#include "cparse.h" +#include <limits.h> +#include <ctype.h> +#include <errno.h> +#include <stdint.h> +#include "pydoc.h" + +#define PYSHADOW_MEMBER  0x2 +#define WARN_PYTHON_MULTIPLE_INH 405 + +#define PYTHON_INT_MAX (2147483647) +#define PYTHON_INT_MIN (-2147483647-1) + +static String *const_code = 0; +static String *module = 0; +static String *package = 0; +static String *mainmodule = 0; +static String *interface = 0; +static String *global_name = 0; +static int shadow = 1; +static int use_kw = 0; +static int director_method_index = 0; +static int builtin = 0; + +static File *f_begin = 0; +static File *f_runtime = 0; +static File *f_runtime_h = 0; +static File *f_header = 0; +static File *f_wrappers = 0; +static File *f_directors = 0; +static File *f_directors_h = 0; +static File *f_init = 0; +static File *f_shadow_py = 0; +static String *f_shadow = 0; +static String *f_shadow_begin = 0; +static Hash *f_shadow_imports = 0; +static String *f_shadow_after_begin = 0; +static String *f_shadow_stubs = 0; +static Hash *builtin_getset = 0; +static Hash *builtin_closures = 0; +static Hash *class_members = 0; +static File *f_builtins = 0; +static String *builtin_tp_init = 0; +static String *builtin_methods = 0; +static String *builtin_default_unref = 0; +static String *builtin_closures_code = 0; + +static String *methods; +static String *methods_proxydocs; +static String *class_name; +static String *shadow_indent = 0; +static int in_class = 0; +static int no_header_file = 0; +static int max_bases = 0; +static int builtin_bases_needed = 0; + +/* C++ Support + Shadow Classes */ + +static int have_constructor = 0; +static int have_repr = 0; +static bool have_builtin_static_member_method_callback = false; +static bool have_fast_proxy_static_member_method_callback = false; +static String *real_classname; + +/* Thread Support */ +static int threads = 0; +static int nothreads = 0; + +/* Other options */ +static int dirvtable = 0; +static int doxygen = 0; +static int fastunpack = 1; +static int fastproxy = 0; +static int olddefs = 0; +static int castmode = 0; +static int extranative = 0; +static int nortti = 0; +static int relativeimport = 0; +static int flat_static_method = 0; + +/* flags for the make_autodoc function */ +namespace { +enum autodoc_t { +  AUTODOC_CLASS, +  AUTODOC_CTOR, +  AUTODOC_DTOR, +  AUTODOC_STATICFUNC, +  AUTODOC_FUNC, +  AUTODOC_METHOD, +  AUTODOC_CONST, +  AUTODOC_VAR +}; +} + +static const char *usage1 = "\ +Python Options (available with -python)\n\ +     -builtin        - Create Python built-in types rather than proxy classes, for better performance\n\ +     -castmode       - Enable the casting mode, which allows implicit cast between types in Python\n\ +     -debug-doxygen-parser     - Display doxygen parser module debugging information\n\ +     -debug-doxygen-translator - Display doxygen translator module debugging information\n\ +     -dirvtable      - Generate a pseudo virtual table for directors for faster dispatch\n\ +     -doxygen        - Convert C++ doxygen comments to pydoc comments in proxy classes\n\ +     -extranative    - Return extra native wrappers for C++ std containers wherever possible\n\ +     -fastproxy      - Use fast proxy mechanism for member methods\n\ +     -flatstaticmethod         - Generate additional flattened Python methods for C++ static methods\n\ +     -globals <name> - Set <name> used to access C global variable (default: 'cvar')\n\ +     -interface <mod>- Set low-level C/C++ module name to <mod> (default: module name prefixed by '_')\n\ +     -keyword        - Use keyword arguments\n"; +static const char *usage2 = "\ +     -nofastunpack   - Use traditional UnpackTuple method to parse the argument functions\n\ +     -noh            - Don't generate the output header file\n"; +static const char *usage3 = "\ +     -noproxy        - Don't generate proxy classes\n\ +     -nortti         - Disable the use of the native C++ RTTI with directors\n\ +     -nothreads      - Disable thread support for the entire interface\n\ +     -olddefs        - Keep the old method definitions when using -fastproxy\n\ +     -relativeimport - Use relative Python imports\n\ +     -threads        - Add thread support for all the interface\n\ +     -O              - Enable the following optimization options:\n\ +                         -fastdispatch -fastproxy -fvirtual\n\ +\n"; + +static String *getSlot(Node *n = NULL, const char *key = NULL, String *default_slot = NULL) { +  static String *zero = NewString("0"); +  String *val = n && key && *key ? Getattr(n, key) : NULL; +  return val ? val : default_slot ? default_slot : zero; +} + +static void printSlot(File *f, String *slotval, const char *slotname, const char *functype = NULL) { +  String *slotval_override = 0; +  if (functype && Strcmp(slotval, "0") == 0) +    slotval = slotval_override = NewStringf("(%s) %s", functype, slotval); +  int len = Len(slotval); +  int fieldwidth = len > 41 ? (len > 61 ? 0 : 61 - len) : 41 - len; +  Printf(f, "    %s,%*s/* %s */\n", slotval, fieldwidth, "", slotname); +  Delete(slotval_override); +} + +static String *getClosure(String *functype, String *wrapper, int funpack = 0) { +  static const char *functypes[] = { +    "unaryfunc", "SWIGPY_UNARYFUNC_CLOSURE", +    "destructor", "SWIGPY_DESTRUCTOR_CLOSURE", +    "inquiry", "SWIGPY_INQUIRY_CLOSURE", +    "getiterfunc", "SWIGPY_GETITERFUNC_CLOSURE", +    "binaryfunc", "SWIGPY_BINARYFUNC_CLOSURE", +    "ternaryfunc", "SWIGPY_TERNARYFUNC_CLOSURE", +    "ternarycallfunc", "SWIGPY_TERNARYCALLFUNC_CLOSURE", +    "lenfunc", "SWIGPY_LENFUNC_CLOSURE", +    "ssizeargfunc", "SWIGPY_SSIZEARGFUNC_CLOSURE", +    "ssizessizeargfunc", "SWIGPY_SSIZESSIZEARGFUNC_CLOSURE", +    "ssizeobjargproc", "SWIGPY_SSIZEOBJARGPROC_CLOSURE", +    "ssizessizeobjargproc", "SWIGPY_SSIZESSIZEOBJARGPROC_CLOSURE", +    "objobjproc", "SWIGPY_OBJOBJPROC_CLOSURE", +    "objobjargproc", "SWIGPY_OBJOBJARGPROC_CLOSURE", +    "reprfunc", "SWIGPY_REPRFUNC_CLOSURE", +    "hashfunc", "SWIGPY_HASHFUNC_CLOSURE", +    "iternextfunc", "SWIGPY_ITERNEXTFUNC_CLOSURE", +    NULL +  }; + +  static const char *funpack_functypes[] = { +    "unaryfunc", "SWIGPY_UNARYFUNC_CLOSURE", +    "destructor", "SWIGPY_DESTRUCTOR_CLOSURE", +    "inquiry", "SWIGPY_INQUIRY_CLOSURE", +    "getiterfunc", "SWIGPY_GETITERFUNC_CLOSURE", +    "ternaryfunc", "SWIGPY_TERNARYFUNC_CLOSURE", +    "ternarycallfunc", "SWIGPY_TERNARYCALLFUNC_CLOSURE", +    "lenfunc", "SWIGPY_LENFUNC_CLOSURE", +    "ssizeargfunc", "SWIGPY_FUNPACK_SSIZEARGFUNC_CLOSURE", +    "ssizessizeargfunc", "SWIGPY_SSIZESSIZEARGFUNC_CLOSURE", +    "ssizeobjargproc", "SWIGPY_SSIZEOBJARGPROC_CLOSURE", +    "ssizessizeobjargproc", "SWIGPY_SSIZESSIZEOBJARGPROC_CLOSURE", +    "objobjproc", "SWIGPY_FUNPACK_OBJOBJPROC_CLOSURE", +    "objobjargproc", "SWIGPY_OBJOBJARGPROC_CLOSURE", +    "reprfunc", "SWIGPY_REPRFUNC_CLOSURE", +    "hashfunc", "SWIGPY_HASHFUNC_CLOSURE", +    "iternextfunc", "SWIGPY_ITERNEXTFUNC_CLOSURE", +    NULL +  }; + +  if (!functype) +    return NULL; +  char *c = Char(functype); +  int i; +  if (funpack) { +    for (i = 0; funpack_functypes[i] != NULL; i += 2) { +      if (!strcmp(c, funpack_functypes[i])) +	return NewStringf("%s(%s)", funpack_functypes[i + 1], wrapper); +    } +  } else { +    for (i = 0; functypes[i] != NULL; i += 2) { +      if (!strcmp(c, functypes[i])) +	return NewStringf("%s(%s)", functypes[i + 1], wrapper); +    } +  } +  return NULL; +} + +class PYTHON:public Language { +public: +  PYTHON() { +    /* Add code to manage protected constructors and directors */ +    director_prot_ctor_code = NewString(""); +    Printv(director_prot_ctor_code, +	   "if ( $comparison ) { /* subclassed */\n", +	   "  $director_new \n", +	   "} else {\n", "  SWIG_SetErrorMsg(PyExc_RuntimeError,\"accessing abstract class or protected constructor\"); \n", "  SWIG_fail;\n", "}\n", NIL); +    director_multiple_inheritance = 1; +    director_language = 1; +  } + +  ~PYTHON() { +    delete doxygenTranslator; +  } + +  /* ------------------------------------------------------------ +   * Thread Implementation +   * ------------------------------------------------------------ */ +  int threads_enable(Node *n) const { +    return threads && !GetFlagAttr(n, "feature:nothread"); +  } + +  int initialize_threads(String *f_init) { +    if (!threads) { +      return SWIG_OK; +    } +    Printf(f_init, "\n"); +    Printf(f_init, "/* Initialize threading */\n"); +    Printf(f_init, "SWIG_PYTHON_INITIALIZE_THREADS;\n"); + +    return SWIG_OK; +  } + +  virtual void thread_begin_block(Node *n, String *f) { +    if (!GetFlag(n, "feature:nothreadblock")) { +      String *bb = Getattr(n, "feature:threadbeginblock"); +      if (bb) { +	Append(f, bb); +      } else { +	Append(f, "SWIG_PYTHON_THREAD_BEGIN_BLOCK;\n"); +      } +    } +  } + +  virtual void thread_end_block(Node *n, String *f) { +    if (!GetFlag(n, "feature:nothreadblock")) { +      String *eb = Getattr(n, "feature:threadendblock"); +      if (eb) { +	Append(f, eb); +      } else { +	Append(f, "SWIG_PYTHON_THREAD_END_BLOCK;\n"); +      } +    } +  } + +  virtual void thread_begin_allow(Node *n, String *f) { +    if (!GetFlag(n, "feature:nothreadallow")) { +      String *bb = Getattr(n, "feature:threadbeginallow"); +      Append(f, "{\n"); +      if (bb) { +	Append(f, bb); +      } else { +	Append(f, "SWIG_PYTHON_THREAD_BEGIN_ALLOW;\n"); +      } +    } +  } + +  virtual void thread_end_allow(Node *n, String *f) { +    if (!GetFlag(n, "feature:nothreadallow")) { +      String *eb = Getattr(n, "feature:threadendallow"); +      Append(f, "\n"); +      if (eb) { +	Append(f, eb); +      } else { +	Append(f, "SWIG_PYTHON_THREAD_END_ALLOW;"); +      } +      Append(f, "\n}"); +    } +  } + + +  /* ------------------------------------------------------------ +   * main() +   * ------------------------------------------------------------ */ + +  virtual void main(int argc, char *argv[]) { + +    SWIG_library_directory("python"); + +    int doxygen_translator_flags = 0; + +    for (int i = 1; i < argc; i++) { +      if (argv[i]) { +	if (strcmp(argv[i], "-interface") == 0) { +	  if (argv[i + 1]) { +	    interface = NewString(argv[i + 1]); +	    Swig_mark_arg(i); +	    Swig_mark_arg(i + 1); +	    i++; +	  } else { +	    Swig_arg_error(); +	  } +	} else if (strcmp(argv[i], "-globals") == 0) { +	  if (argv[i + 1]) { +	    global_name = NewString(argv[i + 1]); +	    Swig_mark_arg(i); +	    Swig_mark_arg(i + 1); +	    i++; +	  } else { +	    Swig_arg_error(); +	  } +	} else if ((strcmp(argv[i], "-shadow") == 0) || ((strcmp(argv[i], "-proxy") == 0))) { +	  shadow = 1; +	  Swig_mark_arg(i); +	} else if ((strcmp(argv[i], "-noproxy") == 0)) { +	  shadow = 0; +	  Swig_mark_arg(i); +	} else if (strcmp(argv[i], "-keyword") == 0) { +	  use_kw = 1; +	  SWIG_cparse_set_compact_default_args(1); +	  Swig_mark_arg(i); +	} else if (strcmp(argv[i], "-nortti") == 0) { +	  nortti = 1; +	  Swig_mark_arg(i); +	} else if (strcmp(argv[i], "-threads") == 0) { +	  threads = 1; +	  Swig_mark_arg(i); +	} else if (strcmp(argv[i], "-nothreads") == 0) { +	  /* Turn off thread support mode */ +	  nothreads = 1; +	  Swig_mark_arg(i); +	} else if (strcmp(argv[i], "-dirvtable") == 0) { +	  dirvtable = 1; +	  Swig_mark_arg(i); +	} else if (strcmp(argv[i], "-doxygen") == 0) { +	  doxygen = 1; +	  scan_doxygen_comments = 1; +	  Swig_mark_arg(i); +	} else if (strcmp(argv[i], "-debug-doxygen-translator") == 0) { +	  doxygen_translator_flags |= DoxygenTranslator::debug_translator; +	  Swig_mark_arg(i); +	} else if (strcmp(argv[i], "-debug-doxygen-parser") == 0) { +	  doxygen_translator_flags |= DoxygenTranslator::debug_parser; +	  Swig_mark_arg(i); +	} else if (strcmp(argv[i], "-nofastunpack") == 0) { +	  fastunpack = 0; +	  Swig_mark_arg(i); +	} else if (strcmp(argv[i], "-fastproxy") == 0) { +	  fastproxy = 1; +	  Swig_mark_arg(i); +	} else if (strcmp(argv[i], "-olddefs") == 0) { +	  olddefs = 1; +	  Swig_mark_arg(i); +	} else if (strcmp(argv[i], "-castmode") == 0) { +	  castmode = 1; +	  Swig_mark_arg(i); +	} else if (strcmp(argv[i], "-extranative") == 0) { +	  extranative = 1; +	  Swig_mark_arg(i); +	} else if (strcmp(argv[i], "-flatstaticmethod") == 0) { +	  flat_static_method = 1; +	  Swig_mark_arg(i); +	} else if (strcmp(argv[i], "-noh") == 0) { +	  no_header_file = 1; +	  Swig_mark_arg(i); +	} else if (strcmp(argv[i], "-newvwm") == 0) { +	  /* Turn on new value wrapper mode */ +	  /* Undocumented option, did have -help text: New value wrapper mode, use only when everything else fails */ +	  Swig_value_wrapper_mode(1); +	  no_header_file = 1; +	  Swig_mark_arg(i); +	} else if (strcmp(argv[i], "-O") == 0) { +	  fastproxy = 1; +	  Wrapper_fast_dispatch_mode_set(1); +	  Wrapper_virtual_elimination_mode_set(1); +	  Swig_mark_arg(i); +	} else if (strcmp(argv[i], "-help") == 0) { +	  fputs(usage1, stdout); +	  fputs(usage2, stdout); +	  fputs(usage3, stdout); +	} else if (strcmp(argv[i], "-builtin") == 0) { +	  builtin = 1; +	  Preprocessor_define("SWIGPYTHON_BUILTIN", 0); +	  Swig_mark_arg(i); +	} else if (strcmp(argv[i], "-relativeimport") == 0) { +	  relativeimport = 1; +	  Swig_mark_arg(i); +	} else if (strcmp(argv[i], "-cppcast") == 0 || +		   strcmp(argv[i], "-fastinit") == 0 || +		   strcmp(argv[i], "-fastquery") == 0 || +		   strcmp(argv[i], "-fastunpack") == 0 || +		   strcmp(argv[i], "-modern") == 0 || +		   strcmp(argv[i], "-modernargs") == 0 || +		   strcmp(argv[i], "-noproxydel") == 0 || +		   strcmp(argv[i], "-safecstrings") == 0) { +	  Printf(stderr, "Deprecated command line option: %s. Ignored, this option is now always on.\n", argv[i]); +	  Swig_mark_arg(i); +	} else if (strcmp(argv[i], "-py3") == 0) { +	  Printf(stderr, "Deprecated command line option: %s. Ignored, this option is no longer supported.\n", argv[i]); +	  Swig_mark_arg(i); +	} else if (strcmp(argv[i], "-aliasobj0") == 0 || +		   strcmp(argv[i], "-buildnone") == 0 || +		   strcmp(argv[i], "-classic") == 0 || +		   strcmp(argv[i], "-classptr") == 0 || +		   strcmp(argv[i], "-new_repr") == 0 || +		   strcmp(argv[i], "-new_vwm") == 0 || +		   strcmp(argv[i], "-newrepr") == 0 || +		   strcmp(argv[i], "-noaliasobj0") == 0 || +		   strcmp(argv[i], "-nobuildnone") == 0 || +		   strcmp(argv[i], "-nocastmode") == 0 || +		   strcmp(argv[i], "-nocppcast") == 0 || +		   strcmp(argv[i], "-nodirvtable") == 0 || +		   strcmp(argv[i], "-noextranative") == 0 || +		   strcmp(argv[i], "-nofastinit") == 0 || +		   strcmp(argv[i], "-nofastproxy") == 0 || +		   strcmp(argv[i], "-nofastquery") == 0 || +		   strcmp(argv[i], "-nomodern") == 0 || +		   strcmp(argv[i], "-nomodernargs") == 0 || +		   strcmp(argv[i], "-noolddefs") == 0 || +		   strcmp(argv[i], "-nooutputtuple") == 0 || +		   strcmp(argv[i], "-noproxyimport") == 0 || +		   strcmp(argv[i], "-nosafecstrings") == 0 || +		   strcmp(argv[i], "-old_repr") == 0 || +		   strcmp(argv[i], "-oldrepr") == 0 || +		   strcmp(argv[i], "-outputtuple") == 0 || +		   strcmp(argv[i], "-proxydel") == 0) { +	  Printf(stderr, "Deprecated command line option: %s. This option is no longer available.\n", argv[i]); +	  Swig_mark_arg(i); +	  Exit(EXIT_FAILURE); +	} + +      } +    } + +    if (builtin && !shadow) { +      Printf(stderr, "Incompatible options -builtin and -noproxy specified.\n"); +      Exit(EXIT_FAILURE); +    } + +    if (fastproxy) { +      Preprocessor_define("SWIGPYTHON_FASTPROXY", 0); +    } + +    if (doxygen) +      doxygenTranslator = new PyDocConverter(doxygen_translator_flags); + +    if (!global_name) +      global_name = NewString("cvar"); +    Preprocessor_define("SWIGPYTHON 1", 0); +    SWIG_typemap_lang("python"); +    SWIG_config_file("python.swg"); +    allow_overloading(); +  } + + +  /* ------------------------------------------------------------ +   * top() +   * ------------------------------------------------------------ */ + +  virtual int top(Node *n) { +    /* check if directors are enabled for this module.  note: this +     * is a "master" switch, without which no director code will be +     * emitted.  %feature("director") statements are also required +     * to enable directors for individual classes or methods. +     * +     * use %module(directors="1") modulename at the start of the +     * interface file to enable director generation. +     */ +    String *mod_docstring = NULL; +    String *moduleimport = NULL; +    { +      Node *mod = Getattr(n, "module"); +      if (mod) { +	Node *options = Getattr(mod, "options"); +	if (options) { +	  int dirprot = 0; +	  if (Getattr(options, "dirprot")) { +	    dirprot = 1; +	  } +	  if (Getattr(options, "nodirprot")) { +	    dirprot = 0; +	  } +	  if (Getattr(options, "directors")) { +	    allow_directors(); +	    if (dirprot) +	      allow_dirprot(); +	  } +	  if (Getattr(options, "threads")) { +	    threads = 1; +	  } +	  if (Getattr(options, "castmode")) { +	    castmode = 1; +	  } +	  if (Getattr(options, "nocastmode")) { +	    Printf(stderr, "Deprecated module option: %s. This option is no longer supported.\n", "nocastmode"); +	    Exit(EXIT_FAILURE); +	  } +	  if (Getattr(options, "extranative")) { +	    extranative = 1; +	  } +	  if (Getattr(options, "noextranative")) { +	    Printf(stderr, "Deprecated module option: %s. This option is no longer supported.\n", "noextranative"); +	    Exit(EXIT_FAILURE); +	  } +	  if (Getattr(options, "outputtuple")) { +	    Printf(stderr, "Deprecated module option: %s. This option is no longer supported.\n", "outputtuple"); +	    Exit(EXIT_FAILURE); +	  } +	  if (Getattr(options, "nooutputtuple")) { +	    Printf(stderr, "Deprecated module option: %s. This option is no longer supported.\n", "nooutputtuple"); +	    Exit(EXIT_FAILURE); +	  } +	  mod_docstring = Getattr(options, "docstring"); +	  package = Getattr(options, "package"); +	  moduleimport = Getattr(options, "moduleimport"); +	} +      } +    } + +    /* Set comparison with none for ConstructorToFunction */ +    setSubclassInstanceCheck(NewString("$arg != Py_None")); + +    /* Initialize all of the output files */ +    String *outfile = Getattr(n, "outfile"); +    String *outfile_h = !no_header_file ? Getattr(n, "outfile_h") : 0; + +    f_begin = NewFile(outfile, "w", SWIG_output_files()); +    if (!f_begin) { +      FileErrorDisplay(outfile); +      Exit(EXIT_FAILURE); +    } +    f_runtime = NewString(""); +    f_init = NewString(""); +    f_header = NewString(""); +    f_wrappers = NewString(""); +    f_directors_h = NewString(""); +    f_directors = NewString(""); +    builtin_getset = NewHash(); +    builtin_closures = NewHash(); +    builtin_closures_code = NewString(""); +    class_members = NewHash(); +    builtin_methods = NewString(""); +    builtin_default_unref = NewString("delete $self;"); + +    if (builtin) { +      f_builtins = NewString(""); +    } + +    if (directorsEnabled()) { +      if (!no_header_file) { +	f_runtime_h = NewFile(outfile_h, "w", SWIG_output_files()); +	if (!f_runtime_h) { +	  FileErrorDisplay(outfile_h); +	  Exit(EXIT_FAILURE); +	} +      } else { +	f_runtime_h = f_runtime; +      } +    } + +    /* Register file targets with the SWIG file handler */ +    Swig_register_filebyname("header", f_header); +    Swig_register_filebyname("wrapper", f_wrappers); +    Swig_register_filebyname("begin", f_begin); +    Swig_register_filebyname("runtime", f_runtime); +    Swig_register_filebyname("init", f_init); +    Swig_register_filebyname("director", f_directors); +    Swig_register_filebyname("director_h", f_directors_h); + +    const_code = NewString(""); +    methods = NewString(""); +    methods_proxydocs = NewString(""); + +    Swig_banner(f_begin); + +    Swig_obligatory_macros(f_runtime, "PYTHON"); + +    if (directorsEnabled()) { +      Printf(f_runtime, "#define SWIG_DIRECTORS\n"); +    } + +    if (nothreads) { +      Printf(f_runtime, "#define SWIG_PYTHON_NO_THREADS\n"); +    } else if (threads) { +      Printf(f_runtime, "#define SWIG_PYTHON_THREADS\n"); +    } + +    if (!dirvtable) { +      Printf(f_runtime, "#define SWIG_PYTHON_DIRECTOR_NO_VTABLE\n"); +    } + +    if (nortti) { +      Printf(f_runtime, "#ifndef SWIG_DIRECTOR_NORTTI\n"); +      Printf(f_runtime, "#define SWIG_DIRECTOR_NORTTI\n"); +      Printf(f_runtime, "#endif\n"); +    } + +    if (castmode) { +      Printf(f_runtime, "#define SWIG_CASTRANK_MODE\n"); +      Printf(f_runtime, "#define SWIG_PYTHON_CAST_MODE\n"); +    } + +    if (extranative) { +      Printf(f_runtime, "#define SWIG_PYTHON_EXTRA_NATIVE_CONTAINERS\n"); +    } + +    if (builtin) { +      Printf(f_runtime, "#define SWIGPYTHON_BUILTIN\n"); +    } + +    if (fastproxy) { +      Printf(f_runtime, "#define SWIGPYTHON_FASTPROXY\n"); +    } + +    Printf(f_runtime, "\n"); + +    Printf(f_header, "#ifdef SWIG_TypeQuery\n"); +    Printf(f_header, "# undef SWIG_TypeQuery\n"); +    Printf(f_header, "#endif\n"); +    Printf(f_header, "#define SWIG_TypeQuery SWIG_Python_TypeQuery\n"); + + +    /* Set module name */ +    module = Copy(Getattr(n, "name")); +    mainmodule = Getattr(n, "name"); + +    if (directorsEnabled()) { +      Swig_banner(f_directors_h); +      Printf(f_directors_h, "\n"); +      Printf(f_directors_h, "#ifndef SWIG_%s_WRAP_H_\n", module); +      Printf(f_directors_h, "#define SWIG_%s_WRAP_H_\n\n", module); +      if (dirprot_mode()) { +	Printf(f_directors_h, "#include <map>\n"); +	Printf(f_directors_h, "#include <string>\n\n"); +      } + +      Printf(f_directors, "\n\n"); +      Printf(f_directors, "/* ---------------------------------------------------\n"); +      Printf(f_directors, " * C++ director class methods\n"); +      Printf(f_directors, " * --------------------------------------------------- */\n\n"); +      if (outfile_h) { +	String *filename = Swig_file_filename(outfile_h); +	Printf(f_directors, "#include \"%s\"\n\n", filename); +	Delete(filename); +      } +    } + +    /* If shadow classing is enabled, we're going to change the module name to "_module" */ +    String *default_import_code = NewString(""); +    if (shadow) { +      String *filen = NewStringf("%s%s.py", SWIG_output_directory(), Char(module)); +      // If we don't have an interface then change the module name X to _X +      if (interface) +	module = interface; +      else +	Insert(module, 0, "_"); +      if ((f_shadow_py = NewFile(filen, "w", SWIG_output_files())) == 0) { +	FileErrorDisplay(filen); +	Exit(EXIT_FAILURE); +      } +      Delete(filen); +      filen = NULL; + +      f_shadow = NewString(""); +      f_shadow_begin = NewString(""); +      f_shadow_imports = NewHash(); +      f_shadow_after_begin = NewString(""); +      f_shadow_stubs = NewString(""); + +      Swig_register_filebyname("shadow", f_shadow); +      Swig_register_filebyname("python", f_shadow); + +      if (!builtin) { +	/* Import the low-level C/C++ module.  This should be a relative import, +	 * since the shadow module may also have been imported by a relative +	 * import, and there is thus no guarantee that the low-level C/C++ module is on +	 * sys.path.  Relative imports must be explicitly specified from 2.6.0 +	 * onwards (implicit relative imports raised a DeprecationWarning in 2.6, +	 * and fail in 2.7 onwards). +	 * +	 * First check for __package__ which is available from 2.6 onwards, see PEP366. +	 * Next try determine the shadow wrapper's package based on the __name__ it +	 * was given by the importer that loaded it. +	 * If the module is in a package, load the low-level C/C++ module from the +	 * same package, otherwise load it as a global module. +	 */ +        Printv(default_import_code, "# Import the low-level C/C++ module\n", NULL); +        Printv(default_import_code, "if __package__ or \".\" in __name__:\n", NULL); +        Printv(default_import_code, tab4, "from . import ", module, "\n", NULL); +        Printv(default_import_code, "else:\n", NULL); +        Printv(default_import_code, tab4, "import ", module, "\n", NULL); +      } else { +        Printv(default_import_code, "# Pull in all the attributes from the low-level C/C++ module\n", NULL); +        Printv(default_import_code, "if __package__ or \".\" in __name__:\n", NULL); +        Printv(default_import_code, tab4, "from .", module, " import *\n", NULL); +        Printv(default_import_code, "else:\n", NULL); +        Printv(default_import_code, tab4, "from ", module, " import *\n", NULL); +      } + +      if (!builtin) { +	/* Need builtins to qualify names like Exception that might also be +	   defined in this module (try both Python 3 and Python 2 names) */ +	Printv(f_shadow, "try:\n", tab4, "import builtins as __builtin__\n", "except ImportError:\n", tab4, "import __builtin__\n", NULL); +      } + +      if (!builtin && fastproxy) { +	Printf(f_shadow, "\n"); +	Printf(f_shadow, "_swig_new_instance_method = %s.SWIG_PyInstanceMethod_New\n", module); +	Printf(f_shadow, "_swig_new_static_method = %s.SWIG_PyStaticMethod_New\n", module); +      } + +      if (!builtin) { +	Printv(f_shadow, "\n", +	       "def _swig_repr(self):\n", +	       tab4, "try:\n", +	       tab4, tab4, "strthis = \"proxy of \" + self.this.__repr__()\n", +	       tab4, "except __builtin__.Exception:\n", +	       tab4, tab4, "strthis = \"\"\n", +	       tab4, "return \"<%s.%s; %s >\" % (self.__class__.__module__, self.__class__.__name__, strthis,)\n\n", NIL); + +	Printv(f_shadow, "\n", +	       "def _swig_setattr_nondynamic_instance_variable(set):\n", +	       tab4, "def set_instance_attr(self, name, value):\n", +	       tab4, tab4, "if name == \"this\":\n", +	       tab4, tab4, tab4, "set(self, name, value)\n", +	       tab4, tab4, "elif name == \"thisown\":\n", +	       tab4, tab4, tab4, "self.this.own(value)\n", +	       tab4, tab4, "elif hasattr(self, name) and isinstance(getattr(type(self), name), property):\n", +	       tab4, tab4, tab4, "set(self, name, value)\n", +	       tab4, tab4, "else:\n", +	       tab4, tab4, tab4, "raise AttributeError(\"You cannot add instance attributes to %s\" % self)\n", +	       tab4, "return set_instance_attr\n\n", NIL); + +	Printv(f_shadow, "\n", +	       "def _swig_setattr_nondynamic_class_variable(set):\n", +	       tab4, "def set_class_attr(cls, name, value):\n", +	       tab4, tab4, "if hasattr(cls, name) and not isinstance(getattr(cls, name), property):\n", +	       tab4, tab4, tab4, "set(cls, name, value)\n", +	       tab4, tab4, "else:\n", +	       tab4, tab4, tab4, "raise AttributeError(\"You cannot add class attributes to %s\" % cls)\n", +	       tab4, "return set_class_attr\n\n", NIL); + +	Printv(f_shadow, "\n", +	       "def _swig_add_metaclass(metaclass):\n", +	       tab4, "\"\"\"Class decorator for adding a metaclass to a SWIG wrapped class - a slimmed down version of six.add_metaclass\"\"\"\n", +	       tab4, "def wrapper(cls):\n", +	       tab4, tab4, "return metaclass(cls.__name__, cls.__bases__, cls.__dict__.copy())\n", +	       tab4, "return wrapper\n\n", NIL); + +	Printv(f_shadow, "\n", +	       "class _SwigNonDynamicMeta(type):\n", +	       tab4, "\"\"\"Meta class to enforce nondynamic attributes (no new attributes) for a class\"\"\"\n", +	       tab4, "__setattr__ = _swig_setattr_nondynamic_class_variable(type.__setattr__)\n", +	       "\n", NIL); + +	Printv(f_shadow, "\n", NIL); + +	if (directorsEnabled()) +	  Printv(f_shadow, "import weakref\n\n", NIL); +      } +    } +    // Include some information in the code +    Printf(f_header, "\n/*-----------------------------------------------\n              @(target):= %s.so\n\ +  ------------------------------------------------*/\n", module); + +    Printf(f_header, "#if PY_VERSION_HEX >= 0x03000000\n"); +    Printf(f_header, "#  define SWIG_init    PyInit_%s\n\n", module); +    Printf(f_header, "#else\n"); +    Printf(f_header, "#  define SWIG_init    init%s\n\n", module); +    Printf(f_header, "#endif\n"); +    Printf(f_header, "#define SWIG_name    \"%s\"\n", module); + +    Printf(f_wrappers, "#ifdef __cplusplus\n"); +    Printf(f_wrappers, "extern \"C\" {\n"); +    Printf(f_wrappers, "#endif\n"); +    Append(const_code, "static swig_const_info swig_const_table[] = {\n"); +    Append(methods, "static PyMethodDef SwigMethods[] = {\n"); +    Append(methods_proxydocs, "static PyMethodDef SwigMethods_proxydocs[] = {\n"); + +    /* the method exported for replacement of new.instancemethod in Python 3 */ +    add_pyinstancemethod_new(); +    add_pystaticmethod_new(); + +    if (builtin) { +      SwigType *s = NewString("SwigPyObject"); +      SwigType_add_pointer(s); +      SwigType_remember(s); +      Delete(s); +    } + +    /* emit code */ +    Language::top(n); + +    if (directorsEnabled()) { +      // Insert director runtime into the f_runtime file (make it occur before %header section) +      Swig_insert_file("director_common.swg", f_runtime); +      Swig_insert_file("director.swg", f_runtime); +    } + +    /* Close language module */ +    Append(methods, "\t { NULL, NULL, 0, NULL }\n"); +    Append(methods, "};\n"); +    Printf(f_wrappers, "%s\n", methods); +    Append(methods_proxydocs, "\t { NULL, NULL, 0, NULL }\n"); +    Append(methods_proxydocs, "};\n"); +    if ((fastproxy && !builtin) || have_fast_proxy_static_member_method_callback) +      Printf(f_wrappers, "%s\n", methods_proxydocs); + +    if (builtin) { +      Dump(f_builtins, f_wrappers); +    } + +    SwigType_emit_type_table(f_runtime, f_wrappers); + +    Append(const_code, "{0, 0, 0, 0.0, 0, 0}};\n"); +    Printf(f_wrappers, "%s\n", const_code); + +    if (have_fast_proxy_static_member_method_callback) +      Printf(f_init, "  SWIG_Python_FixMethods(SwigMethods_proxydocs, swig_const_table, swig_types, swig_type_initial);\n\n"); + +    initialize_threads(f_init); + +    Printf(f_init, "#if PY_VERSION_HEX >= 0x03000000\n"); +    Printf(f_init, "  return m;\n"); +    Printf(f_init, "#else\n"); +    Printf(f_init, "  return;\n"); +    Printf(f_init, "#endif\n"); +    Printf(f_init, "}\n"); + +    Printf(f_wrappers, "#ifdef __cplusplus\n"); +    Printf(f_wrappers, "}\n"); +    Printf(f_wrappers, "#endif\n"); + +    if (shadow) { +      Swig_banner_target_lang(f_shadow_py, "#"); + +      if (mod_docstring) { +	if (Len(mod_docstring)) { +	  const char *triple_double = "\"\"\""; +	  // follow PEP257 rules: https://www.python.org/dev/peps/pep-0257/ +	  // reported by pep257: https://github.com/GreenSteam/pep257 +	  bool multi_line_ds = Strchr(mod_docstring, '\n') != 0; +	  Printv(f_shadow_py, "\n", triple_double, multi_line_ds ? "\n":"", mod_docstring, multi_line_ds ? "\n":"", triple_double, "\n", NIL); +	} +	Delete(mod_docstring); +	mod_docstring = NULL; +      } + +      if (Len(f_shadow_begin) > 0) +	Printv(f_shadow_py, "\n", f_shadow_begin, "\n", NIL); + +      Printv(f_shadow_py, "\nfrom sys import version_info as _swig_python_version_info\n", NULL); + +      if (Len(f_shadow_after_begin) > 0) +	Printv(f_shadow_py, f_shadow_after_begin, "\n", NIL); + +      if (moduleimport) { +	Replaceall(moduleimport, "$module", module); +	Printv(f_shadow_py, moduleimport, "\n", NIL); +      } else { +	Printv(f_shadow_py, default_import_code, NIL); +      } + +      if (Len(f_shadow) > 0) +	Printv(f_shadow_py, "\n", f_shadow, "\n", NIL); +      if (Len(f_shadow_stubs) > 0) +	Printv(f_shadow_py, f_shadow_stubs, "\n", NIL); +      Delete(f_shadow_py); +    } + +    /* Close all of the files */ +    Dump(f_runtime, f_begin); +    Dump(f_header, f_begin); + +    if (directorsEnabled()) { +      Dump(f_directors_h, f_runtime_h); +      Printf(f_runtime_h, "\n"); +      Printf(f_runtime_h, "#endif\n"); +      if (f_runtime_h != f_begin) +	Delete(f_runtime_h); +      Dump(f_directors, f_begin); +    } + +    Dump(f_wrappers, f_begin); +    if (builtin && builtin_bases_needed) +      Printf(f_begin, "static PyTypeObject *builtin_bases[%d];\n\n", max_bases + 2); +    Wrapper_pretty_print(f_init, f_begin); + +    Delete(default_import_code); +    Delete(f_shadow_after_begin); +    Delete(f_shadow_imports); +    Delete(f_shadow_begin); +    Delete(f_shadow); +    Delete(f_header); +    Delete(f_wrappers); +    Delete(f_builtins); +    Delete(f_init); +    Delete(f_directors); +    Delete(f_directors_h); +    Delete(f_runtime); +    Delete(f_begin); + +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * Emit the wrapper for PyInstanceMethod_New to MethodDef array. +   * This wrapper is used to implement -fastproxy, +   * as a replacement of new.instancemethod in Python 3. +   * ------------------------------------------------------------ */ +  int add_pyinstancemethod_new() { +    if (!builtin && fastproxy) { +      String *name = NewString("SWIG_PyInstanceMethod_New"); +      String *line = NewString(""); +      Printf(line, "\t { \"%s\", %s, METH_O, NULL},\n", name, name); +      Append(methods, line); +      Append(methods_proxydocs, line); +      Delete(line); +      Delete(name); +    } +    return 0; +  } + +  /* ------------------------------------------------------------ +   * Emit the wrapper for PyStaticMethod_New to MethodDef array. +   * This wrapper is used to ensure the correct documentation is +   * generated for static methods when using -fastproxy +   * ------------------------------------------------------------ */ +  int add_pystaticmethod_new() { +    if (!builtin && fastproxy) { +      String *name = NewString("SWIG_PyStaticMethod_New"); +      String *line = NewString(""); +      Printf(line, "\t { \"%s\", %s, METH_O, NULL},\n", name, name); +      Append(methods, line); +      Append(methods_proxydocs, line); +      Delete(line); +      Delete(name); +    } +    return 0; +  } + +  /* ------------------------------------------------------------ +   * subpkg_tail() +   * +   * Return the name of 'other' package relative to 'base'. +   * +   * 1. If 'other' is a sub-package of 'base', returns the 'other' relative to +   *    'base'. +   * 2. If 'other' and 'base' are equal, returns empty string "". +   * 3. In any other case, NULL pointer is returned. +   * +   * The 'base' and 'other' are expected to be fully qualified names. +   * +   * NOTE: none of 'base' nor 'other' can be null. +   * +   * Examples: +   * +   *  #  base       other         tail +   * --  ----       -----         ---- +   *  1  "Foo"      "Foo.Bar" ->  "Bar" +   *  2	 "Foo"      "Foo."    ->  "" +   *  3	 "Foo"      "FooB.ar" ->  NULL +   *  4	 "Foo.Bar"  "Foo.Bar" ->  "" +   *  5  "Foo.Bar"  "Foo"     ->  NULL +   *  6  "Foo.Bar"  "Foo.Gez" ->  NULL +   * +   *  NOTE: the example #2 is actually a syntax error (at input). I believe +   *        swig parser prevents us from this case happening here. +   * ------------------------------------------------------------ */ + +  static String *subpkg_tail(const String *base, const String *other) { +    int baselen = Len(base); +    int otherlen = Len(other); + +    if (Strncmp(other, base, baselen) == 0) { +      if ((baselen < otherlen) && (Char(other))[baselen] == '.') { +        return NewString((Char(other)) + baselen + 1); +      } else if (baselen == otherlen) { +        return NewString(""); +      } else { +        return 0; +      } +    } else { +      return 0; +    } +  } + +  /* ------------------------------------------------------------ +   * abs_import_directive_string() +   * +   * Return a string containing python code to import module. +   * +   * 	pkg     package name or the module being imported +   * 	mod     module name of the module being imported +   * 	pfx     optional prefix to module name +   * +   * NOTE: keep this function consistent with abs_import_name_string(). +   * ------------------------------------------------------------ */ + +  static String *abs_import_directive_string(const String *pkg, const String *mod, const char *pfx = "") { +    String *out = NewString(""); + +    if (pkg && *Char(pkg)) { +      Printf(out, "import %s.%s%s\n", pkg, pfx, mod); +    } else { +      Printf(out, "import %s%s\n", pfx, mod); +    } +    return out; +  } + +  /* ------------------------------------------------------------ +   * rel_import_directive_string() +   * +   * Return a string containing python code to import module that +   * is potentially within a package. +   * +   * 	mainpkg	package name of the module which imports the other module +   * 	pkg     package name or the module being imported +   * 	mod     module name of the module being imported +   * 	pfx     optional prefix to module name +   * +   * NOTE: keep this function consistent with rel_import_name_string(). +   * ------------------------------------------------------------ */ + +  static String *rel_import_directive_string(const String *mainpkg, const String *pkg, const String *mod, const char *pfx = "") { + +    /* NOTE: things are not so trivial. This is what we do here (by examples): +     * +     * 0. To import module 'foo', which is not in any package, we do absolute +     *    import: +     * +     *       import foo +     * +     * 1. To import 'pkg1.pkg2.foo', when mainpkg != "pkg1" and +     *    mainpkg != "pkg1.pkg2" or when mainpkg is not given we do absolute +     *    import: +     * +     *          import pkg1.pkg2.foo +     * +     * 2. To import module pkg1.foo, when mainpkg == "pkg1", we do: +     * +     *    - for py3 = 0: +     * +     *          import foo +     * +     *    - for py3 = 1: +     * +     *          from . import foo +     * +     * 3. To import "pkg1.pkg2.pkg3.foo", when mainpkg = "pkg1", we do: +     * +     *    - for py3 == 0: +     * +     *          import pkg2.pkg3.foo +     * +     *    - for py3 == 1: +     * +     *          from . import pkg2  # [1] +     *          import pkg1.pkg2.pkg3.foo +     * +     * NOTE: [1] is necessary for pkg2.foo to be present in the importing module +     */ + +    String *apkg = 0; // absolute (FQDN) package name of pkg +    String *rpkg = 0; // relative package name +    int py3_rlen1 = 0; // length of 1st level sub-package name, used by py3 +    String *out = NewString(""); + +    if (pkg && *Char(pkg)) { +      if (mainpkg) { +	String *tail = subpkg_tail(mainpkg, pkg); +	if (tail) { +	  if (*Char(tail)) { +	    rpkg = NewString(tail); +	    const char *py3_end1 = Strchr(rpkg, '.'); +	    if (!py3_end1) +	      py3_end1 = (Char(rpkg)) + Len(rpkg); +	    py3_rlen1 = (int)(py3_end1 - Char(rpkg)); +	  } else { +	    rpkg = NewString(""); +	  } +	  Delete(tail); +	} else { +	  apkg = NewString(pkg); +	} +      } else { +	apkg = NewString(pkg); +      } +    } else { +      apkg = NewString(""); +    } + +    if (apkg) { +      Printf(out, "import %s%s%s%s\n", apkg, *Char(apkg) ? "." : "", pfx, mod); +      Delete(apkg); +    } else { +      if (py3_rlen1) +	Printf(out, "from . import %.*s\n", py3_rlen1, rpkg); +      Printf(out, "from .%s import %s%s\n", rpkg, pfx, mod); +      Delete(rpkg); +    } +    return out; +  } + +  /* ------------------------------------------------------------ +   * import_directive_string() +   * ------------------------------------------------------------ */ + +  static String *import_directive_string(const String *mainpkg, const String *pkg, const String *mod, const char *pfx = "") { +    if (!relativeimport) { +      return abs_import_directive_string(pkg, mod, pfx); +    } else { +      return rel_import_directive_string(mainpkg, pkg, mod, pfx); +    } +  } + +  /* ------------------------------------------------------------ +   * abs_import_name_string() +   * +   * Return a string with the name of a symbol (perhaps imported +   * from external module by absolute import directive). +   * +   * mainpkg  package name of current module +   * mainmod  module name of current module +   * pkg      package name of (perhaps other) module +   * mod      module name of (perhaps other) module +   * sym      symbol name +   * +   * NOTE: mainmod, mod, and sym can't be NULL. +   * NOTE: keep this function consistent with abs_import_directive_string() +   * ------------------------------------------------------------ */ + +  static String *abs_import_name_string(const String *mainpkg, const String *mainmod, const String *pkg, const String *mod, const String *sym) { +    String *out = NewString(""); +    if (pkg && *Char(pkg)) { +      if (mainpkg && *Char(mainpkg)) { +        if (Strcmp(mainpkg,pkg) != 0 || Strcmp(mainmod, mod) != 0) { +          Printf(out, "%s.%s.", pkg, mod); +        } +      } else { +        Printf(out, "%s.%s.", pkg, mod); +      } +    } else if ((mainpkg && *Char(mainpkg)) || Strcmp(mainmod, mod) != 0) { +      Printf(out, "%s.", mod); +    } +    Append(out, sym); +    return out; +  } + +  /* ------------------------------------------------------------ +   * rel_import_name_string() +   * +   * Return a string with the name of a symbol (perhaps imported +   * from external module by relative import directive). +   * +   * mainpkg  package name of current module +   * mainmod  module name of current module +   * pkg      package name of (perhaps other) module +   * mod      module name of (perhaps other) module +   * sym      symbol name +   * +   * NOTE: mainmod, mod, and sym can't be NULL. +   * NOTE: keep this function consistent with rel_import_directive_string() +   * ------------------------------------------------------------ */ + +  static String *rel_import_name_string(const String *mainpkg, const String *mainmod, const String *pkg, const String *mod, const String *sym) { +    String *out = NewString(""); +    if (pkg && *Char(pkg)) { +      String *tail = 0; +      if (mainpkg) +        tail = subpkg_tail(mainpkg, pkg); +      if (!tail) +        tail = NewString(pkg); +      if (*Char(tail)) { +        Printf(out, "%s.%s.", tail, mod); +      } else if (Strcmp(mainmod, mod) != 0) { +        Printf(out, "%s.", mod); +      } +      Delete(tail); +    } else if ((mainpkg && *Char(mainpkg)) || Strcmp(mainmod, mod) != 0) { +      Printf(out, "%s.", mod); +    } +    Append(out, sym); +    return out; +  } + +  /* ------------------------------------------------------------ +   * import_name_string() +   * ------------------------------------------------------------ */ + +  static String *import_name_string(const String *mainpkg, const String *mainmod, const String *pkg, const String *mod, const String *sym) { +    if (!relativeimport) { +      return abs_import_name_string(mainpkg,mainmod,pkg,mod,sym); +    } else { +      return rel_import_name_string(mainpkg,mainmod,pkg,mod,sym); +    } +  } + +  /* ------------------------------------------------------------ +   * importDirective() +   * ------------------------------------------------------------ */ + +  virtual int importDirective(Node *n) { +    if (shadow) { +      String *modname = Getattr(n, "module"); + +      if (modname) { +	// Find the module node for this imported module.  It should be the +	// first child but search just in case. +	Node *mod = firstChild(n); +	while (mod && Strcmp(nodeType(mod), "module") != 0) +	  mod = nextSibling(mod); + +	Node *options = Getattr(mod, "options"); +	String *pkg = options ? Getattr(options, "package") : 0; + +	if (!options || (!Getattr(options, "noshadow") && !Getattr(options, "noproxy"))) { +	  String *_import = import_directive_string(package, pkg, modname, "_"); +	  if (!GetFlagAttr(f_shadow_imports, _import)) { +	    String *import = import_directive_string(package, pkg, modname); +	    Printf(builtin ? f_shadow_after_begin : f_shadow, "%s", import); +	    Delete(import); +	    SetFlag(f_shadow_imports, _import); +	  } +	  Delete(_import); +	} + +      } +    } +    return Language::importDirective(n); +  } + +  /* ------------------------------------------------------------ +   * funcCall() +   * +   * Emit shadow code to call a function in the extension +   * module. Using proper argument and calling style for +   * given node n. +   * ------------------------------------------------------------ */ +  String *funcCall(String *name, String *parms) { +    String *str = NewString(""); + +    Printv(str, module, ".", name, "(", parms, ")", NIL); +    return str; +  } + +  /* ------------------------------------------------------------ +   * indent_pythoncode() +   * +   * Format (indent) Python code. +   * Remove leading whitespace from 'code' and re-indent using +   * the indentation string in 'indent'. +   * ------------------------------------------------------------ */ + +  String *indent_pythoncode(const String *code, const_String_or_char_ptr indent, String *file, int line, const char *directive_name) { +    String *out = NewString(""); +    String *temp; +    char *t; +    if (!indent) +      indent = ""; + +    temp = NewString(code); + +    t = Char(temp); +    if (*t == '{') { +      Delitem(temp, 0); +      Delitem(temp, DOH_END); +    } + +    /* Split the input text into lines */ +    List *clist = SplitLines(temp); +    Delete(temp); + +    // Line number within the pythoncode. +    int py_line = 0; + +    String *initial = 0; +    Iterator si; + +    /* Get the initial indentation.  Skip lines which only contain whitespace +     * and/or a comment, as the indentation of those doesn't matter: +     * +     *     A logical line that contains only spaces, tabs, formfeeds and +     *     possibly a comment, is ignored (i.e., no NEWLINE token is +     *     generated). +     * +     * see: +     * https://docs.python.org/2/reference/lexical_analysis.html#blank-lines +     * https://docs.python.org/3/reference/lexical_analysis.html#blank-lines +     */ +    for (si = First(clist); si.item; si = Next(si), ++py_line) { +      const char *c = Char(si.item); +      int i; +      for (i = 0; isspace((unsigned char)c[i]); i++) { +	// Scan forward until we find a non-space (which may be a null byte). +      } +      char ch = c[i]; +      if (ch && ch != '#') { +	// Found a line with actual content. +	initial = NewStringWithSize(c, i); +	break; +      } +      if (ch) { +	Printv(out, indent, c, NIL); +      } +      Putc('\n', out); +    } + +    // Process remaining lines. +    for ( ; si.item; si = Next(si), ++py_line) { +      const char *c = Char(si.item); +      // If no prefixed line was found, the above loop should have completed. +      assert(initial); + +      int i; +      for (i = 0; isspace((unsigned char)c[i]); i++) { +	// Scan forward until we find a non-space (which may be a null byte). +      } +      char ch = c[i]; +      if (!ch) { +	// Line is just whitespace - emit an empty line. +	Putc('\n', out); +	continue; +      } + +      if (ch == '#') { +	// Comment - the indentation doesn't matter to python, but try to +	// adjust the whitespace for the benefit of human readers (though SWIG +	// currently seems to always remove any whitespace before a '#' before +	// we get here, in which case we'll just leave the comment at the start +	// of the line). +	if (i >= Len(initial)) { +	  Printv(out, indent, NIL); +	} + +	Printv(out, c + i, "\n", NIL); +	continue; +      } + +      if (i < Len(initial)) { +	// There's non-whitespace in the initial prefix of this line. +	Swig_error(file, line, "Line indented less than expected (line %d of %s) as no line should be indented less than the indentation in line 1\n", py_line, directive_name); +	Printv(out, indent, c, "\n", NIL); +      } else { +	if (memcmp(c, Char(initial), Len(initial)) == 0) { +	  // Prefix matches initial, so just remove it. +	  Printv(out, indent, c + Len(initial), "\n", NIL); +	  continue; +	} +	Swig_warning(WARN_PYTHON_INDENT_MISMATCH, +		     file, line, "Whitespace indentation is inconsistent compared to earlier lines (line %d of %s)\n", py_line, directive_name); +	// To avoid gratuitously breaking interface files which worked with +	// SWIG <= 3.0.5, we remove a prefix of the same number of bytes for +	// lines which start with different whitespace to the line we got +	// 'initial' from. +	Printv(out, indent, c + Len(initial), "\n", NIL); +      } +    } +    Delete(clist); +    return out; +  } + +  /* ------------------------------------------------------------ +   * indent_docstring() +   * +   * Format (indent) a Python docstring. +   * Remove leading whitespace from 'code' and re-indent using +   * the indentation string in 'indent'. +   * ------------------------------------------------------------ */ + +  String *indent_docstring(const String *code, const_String_or_char_ptr indent) { +    String *out = NewString(""); +    String *temp; +    char *t; +    if (!indent) +      indent = ""; + +    temp = NewString(code); + +    t = Char(temp); +    if (*t == '{') { +      Delitem(temp, 0); +      Delitem(temp, DOH_END); +    } + +    /* Split the input text into lines */ +    List *clist = SplitLines(temp); +    Delete(temp); + +    Iterator si; + +    int truncate_characters_count = INT_MAX; +    for (si = First(clist); si.item; si = Next(si)) { +      const char *c = Char(si.item); +      int i; +      for (i = 0; isspace((unsigned char)c[i]); i++) { +	// Scan forward until we find a non-space (which may be a null byte). +      } +      char ch = c[i]; +      if (ch) { +	// Found a line which isn't just whitespace +	if (i < truncate_characters_count) +	  truncate_characters_count = i; +      } +    } + +    if (truncate_characters_count == INT_MAX) +      truncate_characters_count = 0; + +    for (si = First(clist); si.item; si = Next(si)) { +      const char *c = Char(si.item); + +      int i; +      for (i = 0; isspace((unsigned char)c[i]); i++) { +	// Scan forward until we find a non-space (which may be a null byte). +      } +      char ch = c[i]; +      if (!ch) { +	// Line is just whitespace - emit an empty line. +	Putc('\n', out); +	continue; +      } + +      Printv(out, indent, c + truncate_characters_count, "\n", NIL); +    } +    Delete(clist); +    return out; +  } + +  /* ------------------------------------------------------------ +   * autodoc level declarations +   * ------------------------------------------------------------ */ + +  enum autodoc_l { +    NO_AUTODOC = -2,		// no autodoc +    STRING_AUTODOC = -1,	// use provided string +    NAMES_AUTODOC = 0,		// only parameter names +    TYPES_AUTODOC = 1,		// parameter names and types +    EXTEND_AUTODOC = 2,		// extended documentation and parameter names +    EXTEND_TYPES_AUTODOC = 3	// extended documentation and parameter types + names +  }; + + +  autodoc_l autodoc_level(String *autodoc) { +    autodoc_l dlevel = NO_AUTODOC; +    char *c = Char(autodoc); +    if (c) { +      if (isdigit(c[0])) { +	dlevel = (autodoc_l) atoi(c); +      } else { +	if (strcmp(c, "extended") == 0) { +	  dlevel = EXTEND_AUTODOC; +	} else { +	  dlevel = STRING_AUTODOC; +	} +      } +    } +    return dlevel; +  } + + +  /* ------------------------------------------------------------ +   * have_docstring() +   * +   * Check if there is a docstring directive and it has text, +   * or there is an autodoc flag set +   * ------------------------------------------------------------ */ + +  bool have_docstring(Node *n) { +    String *str = Getattr(n, "feature:docstring"); +    return ((str && Len(str) > 0) +	|| (Getattr(n, "feature:autodoc") && !GetFlag(n, "feature:noautodoc")) +	|| (doxygen && doxygenTranslator->hasDocumentation(n)) +      ); +  } + +  /* ------------------------------------------------------------ +   * build_combined_docstring() +   * +   * Build the full docstring: +   * Use the docstring if there is one present otherwise +   * use the Doxygen comment if there is one present. +   * Ignore autodoc if there is a Doxygen comment, otherwise +   * create the autodoc string and append to any docstring. +   * +   * Return new string to be deleted by caller (never NIL but +   * may be empty if there is no docstring). +   * ------------------------------------------------------------ */ + +  String *build_combined_docstring(Node *n, autodoc_t ad_type, const String *indent = "", bool low_level = false) { +    bool add_autodoc = true; +    String *docstr = Getattr(n, "feature:docstring"); +    if (docstr) { +      // Simplify the code below by just ignoring empty docstrings. +      if (!Len(docstr)) +	docstr = NULL; +      else +	docstr = Copy(docstr); +    } + +    if (docstr) { +      char *t = Char(docstr); +      if (*t == '{') { +	Delitem(docstr, 0); +	Delitem(docstr, DOH_END); +      } +    } + +    if (!docstr) { +      if (doxygen && doxygenTranslator->hasDocumentation(n)) { +	docstr = Getattr(n, "python:docstring"); +	if (!docstr) { +	  docstr = doxygenTranslator->getDocumentation(n, 0); + +	  // Avoid rebuilding it again the next time: notice that we can't do +	  // this for the combined doc string as autodoc part of it depends on +	  // the sym:name of the node and it is changed while handling it, so +	  // the cached results become incorrect. But Doxygen docstring only +	  // depends on the comment which is not going to change, so we can +	  // safely cache it. +	  Setattr(n, "python:docstring", Copy(docstr)); +	} else { +	  // Must copy here since if the docstring is multi-line, the String* +	  // here will get Deleted below, which is bad if it is a pointer to +	  // the cached object! +	  docstr = Copy(docstr); +	} +	add_autodoc = false; +      } +    } + +    if (add_autodoc && Getattr(n, "feature:autodoc") && !GetFlag(n, "feature:noautodoc")) { +      String *autodoc = make_autodoc(n, ad_type, low_level); +      if (autodoc && Len(autodoc) > 0) { +	if (docstr) { +	  Append(autodoc, "\n"); +	  Append(autodoc, docstr); +	} + +	String *tmp = autodoc; +	autodoc = docstr; +	docstr = tmp; +      } + +      Delete(autodoc); +    } + +    if (!docstr) +      docstr = NewString(""); + +    // If there is more than one line then make docstrings like this: +    // +    //      """ +    //      This is line1 +    //      And here is line2 followed by the rest of them +    //      """ +    // +    // otherwise, put it all on a single line +    if (Strchr(docstr, '\n')) { +      String *tmp = NewString(""); +      Append(tmp, "\n"); +      Append(tmp, indent_docstring(docstr, indent)); +      Append(tmp, indent); +      Delete(docstr); +      docstr = tmp; +    } + +    return docstr; +  } + +  /* ------------------------------------------------------------ +   * docstring() +   * +   * Get the docstring text, stripping off {} if necessary, +   * and enclose in triple double quotes.  If autodoc is also +   * set then it will build a combined docstring. +   * ------------------------------------------------------------ */ + +  String *docstring(Node *n, autodoc_t ad_type, const String *indent, bool low_level = false) { +    String *docstr = build_combined_docstring(n, ad_type, indent, low_level); +    const int len = Len(docstr); +    if (!len) +      return docstr; + +    // Notice that all comments are created as raw strings (prefix "r"), +    // because '\' is used often in comments, but may break Python module from +    // loading. For example, in doxy comment one may write path in quotes: +    // +    //     This is path to file "C:\x\file.txt" +    // +    // Python will not load the module with such comment because of illegal +    // escape '\x'. '\' may additionally appear in verbatim or htmlonly sections +    // of doxygen doc, Latex expressions, ... +    String *doc = NewString(""); + +    // Determine which kind of quotes to use as delimiters: for single line +    // strings we can avoid problems with having a quote as the last character +    // of the docstring by using different kind of quotes as delimiters. For +    // multi-line strings this problem doesn't arise, as we always have a new +    // line or spaces at the end of it, but it still does no harm to do it for +    // them too. +    // +    // Note: we use double quotes by default, i.e. if there is no reason to +    // prefer using single ones, for consistency with the older SWIG versions. +    const bool useSingleQuotes = (Char(docstr))[len - 1] == '"'; + +    Append(doc, useSingleQuotes ? "r'''" : "r\"\"\""); + +    // We also need to avoid having triple quotes of whichever type we use, as +    // this would break Python doc string syntax too. Unfortunately there is no +    // way to have triple quotes inside of raw-triple-quoted string, so we have +    // to break the string in parts and rely on concatenation of the adjacent +    // string literals. +    if (useSingleQuotes) +      Replaceall(docstr, "'''", "''' \"'''\" '''"); +    else +      Replaceall(docstr, "\"\"\"", "\"\"\" '\"\"\"' \"\"\""); + +    Append(doc, docstr); +    Append(doc, useSingleQuotes ? "'''" : "\"\"\""); +    Delete(docstr); + +    return doc; +  } + +  /* ------------------------------------------------------------ +   * cdocstring() +   * +   * Get the docstring text as it would appear in C-language +   * source code (but without quotes around it). +   * ------------------------------------------------------------ */ + +  String *cdocstring(Node *n, autodoc_t ad_type, bool low_level = false) { +    String *ds = build_combined_docstring(n, ad_type, "", low_level); +    Replaceall(ds, "\\", "\\\\"); +    Replaceall(ds, "\"", "\\\""); +    Replaceall(ds, "\n", "\\n\"\n\t\t\""); +    return ds; +  } + +  /* ----------------------------------------------------------------------------- +   * addMissingParameterNames() +   * +   * For functions that have not had nameless parameters set in the Language class. +   * +   * Inputs: +   *   plist - entire parameter list +   *   arg_num - the number to start from when naming arguments +   * Side effects: +   *   The "lname" attribute in each parameter in plist will be contain a parameter name +   * ----------------------------------------------------------------------------- */ + +  void addMissingParameterNames(Node *n, ParmList *plist, int arg_num) { +    Parm *p = plist; +    int i = arg_num; +    while (p) { +      if (!Getattr(p, "lname")) { +	String *name = makeParameterName(n, p, i); +	Setattr(p, "lname", name); +	Delete(name); +      } +      i++; +      p = nextSibling(p); +    } +  } + +  /* ------------------------------------------------------------ +   * make_autodocParmList() +   * +   * Generate the documentation for the function parameters +   * Parameters: +   *    arg_num:         The number to start assigning unnamed arguments from +   *    func_annotation: Function annotation support +   * ------------------------------------------------------------ */ + +  String *make_autodocParmList(Node *n, bool showTypes, int arg_num = 1, bool calling = false, bool func_annotation = false) { + +    String *doc = NewString(""); +    String *pdocs = 0; +    ParmList *plist = CopyParmList(Getattr(n, "parms")); +    Parm *p; +    Parm *pnext; + +    if (calling) +      func_annotation = false; + +    addMissingParameterNames(n, plist, arg_num); // for $1_name substitutions done in Swig_typemap_attach_parms +    Swig_typemap_attach_parms("in", plist, 0); +    Swig_typemap_attach_parms("doc", plist, 0); + +    if (Strcmp(ParmList_protostr(plist), "void") == 0) { +      //No parameters actually +      return doc; +    } + +    for (p = plist; p; p = pnext) { +      String *tm = Getattr(p, "tmap:in"); +      if (tm) { +	pnext = Getattr(p, "tmap:in:next"); +	if (checkAttribute(p, "tmap:in:numinputs", "0")) { +	  continue; +	} +      } else { +	pnext = nextSibling(p); +      } + +      String *name = 0; +      String *type = 0; +      String *value = 0; +      String *pdoc = Getattr(p, "tmap:doc"); +      if (pdoc) { +	name = Getattr(p, "tmap:doc:name"); +	type = Getattr(p, "tmap:doc:type"); +	value = Getattr(p, "tmap:doc:value"); +      } + +      // Skip the "self" argument - it is added to the parameter list automatically +      // and shouldn't be included in the Parameters block +      if (Getattr(p, "self")) { +	continue; +      } + +      // Note: the generated name should be consistent with that in kwnames[] +      String *made_name = 0; +      if (!name) { +	name = made_name = makeParameterName(n, p, arg_num); +      } + +      // Increment the argument number once we are sure this is a real argument to count +      arg_num++; + +      type = type ? type : Getattr(p, "type"); +      value = value ? value : Getattr(p, "value"); + +      if (SwigType_isvarargs(type)) { +	Delete(made_name); +	break; +      } + +      if (Len(doc)) { +	// add a comma to the previous one if any +	Append(doc, ", "); +      } + +      // Do the param type too? +      Node *nn = classLookup(Getattr(p, "type")); +      String *type_str = nn ? Copy(Getattr(nn, "sym:name")) : SwigType_str(type, 0); +      if (showTypes) +	Printf(doc, "%s ", type_str); + +      Append(doc, name); +      if (pdoc) { +	if (!pdocs) +	  // numpydoc style: https://github.com/numpy/numpy/blob/master/doc/HOWTO_DOCUMENT.rst.txt +	  pdocs = NewString("\nParameters\n----------\n"); +	Printf(pdocs, "%s\n", pdoc); +      } +      // Write the function annotation +      if (func_annotation) +	Printf(doc, ": \"%s\"", type_str); + +      // Write default value +      if (value && !calling) { +	String *new_value = convertValue(value, Getattr(p, "type")); +	if (new_value) { +	  value = new_value; +	} else { +	  // Even if the value is not representable in the target language, still use it in the documentation, for compatibility with the previous SWIG versions +	  // and because it can still be useful to see the C++ expression there. +	  Node *lookup = Swig_symbol_clookup(value, 0); +	  if (lookup) +	    value = Getattr(lookup, "sym:name"); +	} +	Printf(doc, "=%s", value); + +	if (new_value) +	  Delete(new_value); +      } +      Delete(type_str); +      Delete(made_name); +    } +    if (pdocs) +      Setattr(n, "feature:pdocs", pdocs); +    Delete(plist); +    return doc; +  } + +  /* ------------------------------------------------------------ +   * make_autodoc() +   * +   * Build a docstring for the node, using parameter and other +   * info in the parse tree.  If the value of the autodoc +   * attribute is "0" then do not include parameter types, if +   * it is "1" (the default) then do.  If it has some other +   * value then assume it is supplied by the extension writer +   * and use it directly. +   * ------------------------------------------------------------ */ + +  String *make_autodoc(Node *n, autodoc_t ad_type, bool low_level = false) { +    int extended = 0; +    bool first_func = true; +    // If the function is overloaded then this function is called +    // for the last one.  Rewind to the first so the docstrings are +    // in order. +    while (Getattr(n, "sym:previousSibling")) +      n = Getattr(n, "sym:previousSibling"); + +    String *doc = NewString(""); +    while (n) { +      bool showTypes = false; +      bool skipAuto = false; +      String *autodoc = Getattr(n, "feature:autodoc"); +      autodoc_l dlevel = autodoc_level(autodoc); +      switch (dlevel) { +      case NO_AUTODOC: +	break; +      case NAMES_AUTODOC: +	showTypes = false; +	break; +      case TYPES_AUTODOC: +	showTypes = true; +	break; +      case EXTEND_AUTODOC: +	extended = 1; +	showTypes = false; +	break; +      case EXTEND_TYPES_AUTODOC: +	extended = 1; +	showTypes = true; +	break; +      case STRING_AUTODOC: +	Append(doc, autodoc); +	skipAuto = true; +	break; +      } + +      if (!skipAuto) { +	/* Check if a documentation name was given for either the low-level C API or high-level Python shadow API */ +	String *symname = Getattr(n, low_level ? "doc:low:name" : "doc:high:name"); +	if (!symname) { +	  symname = Getattr(n, "sym:name"); +	} + +	SwigType *type = Getattr(n, "type"); +	String *type_str = NULL; + +	// If the function has default arguments, then that documentation covers this version too +	if (Getattr(n, "defaultargs") != NULL) { +	  n = Getattr(n, "sym:nextSibling"); +	  continue; +	} + +	if (!first_func) +	  Append(doc, "\n"); + +	if (type) { +	  if (Strcmp(type, "void") == 0) { +	    type_str = NULL; +	  } else { +	    Node *nn = classLookup(type); +	    type_str = nn ? Copy(Getattr(nn, "sym:name")) : SwigType_str(type, 0); +	  } +	} + +	/* Treat the low-level C API functions for getting/setting variables as methods for documentation purposes */ +	String *kind = Getattr(n, "kind"); +	if (kind && Strcmp(kind, "variable") == 0) { +	  if (ad_type == AUTODOC_FUNC) { +	    ad_type = AUTODOC_METHOD; +	  } +	} +	/* Treat destructors as methods for documentation purposes */ +	String *nodeType = Getattr(n, "nodeType"); +	if (nodeType && Strcmp(nodeType, "destructor") == 0) { +	  if (ad_type == AUTODOC_FUNC) { +	    ad_type = AUTODOC_METHOD; +	  } +	} + +	switch (ad_type) { +	case AUTODOC_CLASS: +	  { +	    // Only do the autodoc if there isn't a docstring for the class +	    String *str = Getattr(n, "feature:docstring"); +	    if (!str || Len(str) == 0) { +	      if (builtin) { +		String *name = Getattr(n, "name"); +		String *rname = add_explicit_scope(SwigType_namestr(name)); +		Printf(doc, "%s", rname); +		Delete(rname); +	      } else { +		if (CPlusPlus) { +		  Printf(doc, "Proxy of C++ %s class.", SwigType_namestr(real_classname)); +		} else { +		  Printf(doc, "Proxy of C %s struct.", SwigType_namestr(real_classname)); +		} +	      } +	    } +	  } +	  break; +	case AUTODOC_CTOR: +	  if (Strcmp(class_name, symname) == 0) { +	    String *paramList = make_autodocParmList(n, showTypes, 2); +	    Printf(doc, "__init__("); +	    if (showTypes) +	      Printf(doc, "%s ", class_name); +	    if (Len(paramList)) +	      Printf(doc, "self, %s) -> %s", paramList, class_name); +	    else +	      Printf(doc, "self) -> %s", class_name); +	  } else +	    Printf(doc, "%s(%s) -> %s", symname, make_autodocParmList(n, showTypes), class_name); +	  break; + +	case AUTODOC_DTOR: +	  if (showTypes) +	    Printf(doc, "__del__(%s self)", class_name); +	  else +	    Printf(doc, "__del__(self)"); +	  break; + +	case AUTODOC_STATICFUNC: +	  Printf(doc, "%s(%s)", symname, make_autodocParmList(n, showTypes)); +	  if (type_str) +	    Printf(doc, " -> %s", type_str); +	  break; + +	case AUTODOC_FUNC: +	  Printf(doc, "%s(%s)", symname, make_autodocParmList(n, showTypes)); +	  if (type_str) +	    Printf(doc, " -> %s", type_str); +	  break; + +	case AUTODOC_METHOD: +	  { +	    String *paramList = make_autodocParmList(n, showTypes, 2); +	    Printf(doc, "%s(", symname); +	    if (showTypes) +	      Printf(doc, "%s ", class_name); +	    if (Len(paramList)) +	      Printf(doc, "self, %s)", paramList); +	    else +	      Printf(doc, "self)"); +	    if (type_str) +	      Printf(doc, " -> %s", type_str); +	  } +	  break; + +	case AUTODOC_CONST: +	  // There is no autodoc support for constants currently, this enum +	  // element only exists to allow calling docstring() with it. +	  return NULL; +	case AUTODOC_VAR: +	  // Variables can also be documented (e.g. through the property() function in python) +	  Printf(doc, "%s", symname); +	  if (showTypes) { +	    String *type = Getattr(n, "tmap:doc:type"); +	    if (!type) +	      type = Getattr(n, "membervariableHandler:type"); +	    if (!type) +	      type = Getattr(n, "type"); +	    Printf(doc, " : %s", type); +	  } +	  break; +	} +	Delete(type_str); + +	// Special case: wrapper functions to get a variable should have no parameters. +	// Because the node is re-used for the setter and getter, the feature:pdocs field will +	// exist for the getter function, so explicitly avoid printing parameters in this case. +	bool variable_getter = kind && Strcmp(kind, "variable") == 0 && Getattr(n, "memberget"); +	if (extended && ad_type != AUTODOC_VAR && !variable_getter) { +	  String *pdocs = Getattr(n, "feature:pdocs"); +	  if (pdocs) { +	    Printv(doc, "\n", pdocs, NULL); +	  } +	} +      } +      // if it's overloaded then get the next decl and loop around again +      n = Getattr(n, "sym:nextSibling"); +      if (n) +	first_func = false; +    } + +    return doc; +  } + +  /* ------------------------------------------------------------ +   * convertIntegerValue() +   * +   * Check if string v is an integer and can be represented in +   * Python. If so, return an appropriate Python representation, +   * otherwise (or if we are unsure), return NIL. +   * ------------------------------------------------------------ */ +  String *convertIntegerValue(String *v, SwigType *resolved_type) { +    const char *const s = Char(v); +    char *end; +    String *result = NIL; + +    // Check if this is an integer number in any base. +    errno = 0; +    long value = strtol(s, &end, 0); +    if (errno == ERANGE || end == s) +      return NIL; + +    if (*end != '\0') { +      // If there is a suffix after the number, we can safely ignore "l" +      // and (provided the number is unsigned) "u", and also combinations of +      // these, but not anything else. +      for (char *p = end; *p != '\0'; ++p) { +        switch (*p) { +          case 'l': +          case 'L': +	    break; +          case 'u': +          case 'U': +	    if (value < 0) +	      return NIL; +            break; +          default: +            return NIL; +        } +      } +    } +    // So now we are certain that we are indeed dealing with an integer +    // that has a representation as long given by value. + +    // Restrict to guaranteed supported range in Python, see maxint docs: https://docs.python.org/2/library/sys.html#sys.maxint +    // Don't do this pointless check when long is 32 bits or smaller as strtol will have already failed with ERANGE +#if LONG_MAX > PYTHON_INT_MAX || LONG_MIN < PYTHON_INT_MIN +    if (value > PYTHON_INT_MAX || value < PYTHON_INT_MIN) { +      return NIL; +    } +#endif + +    if (Cmp(resolved_type, "bool") == 0) +      // Allow integers as the default value for a bool parameter. +      return NewString(value ? "True" : "False"); + +    if (value == 0) +      return NewString(SwigType_ispointer(resolved_type) ? "None" : "0"); + +    // v may still be octal or hexadecimal: +    const char *p = s; +    if (*p == '+' || *p == '-') +      ++p; +    if (*p == '0' && *(p+1) != 'x' && *(p+1) != 'X') { +      // This must have been an octal number. This is the only case we +      // cannot use in Python directly, since Python 2 and 3 use non- +      // compatible representations. +      result = NewString(*s == '-' ? "int(\"-" : "int(\""); +      String *octal_string = NewStringWithSize(p, (int) (end - p)); +      Append(result, octal_string); +      Append(result, "\", 8)"); +      Delete(octal_string); +      return result; +    } +    result = *end == '\0' ? Copy(v) : NewStringWithSize(s, (int) (end - s)); +    return result; +  } + +  /* ------------------------------------------------------------ +   * convertDoubleValue() +   * +   * Check if the given string looks like a decimal floating point constant +   * and return it if it does, otherwise return NIL. +   * ------------------------------------------------------------ */ +  String *convertDoubleValue(String *v) { +    const char *const s = Char(v); +    char *end; + +    errno = 0; +    double value = strtod(s, &end); +    (void) value; +    if (errno != ERANGE && end != s) { +      // An added complication: at least some versions of strtod() recognize +      // hexadecimal floating point numbers which don't exist in Python, so +      // detect them ourselves and refuse to convert them (this can't be done +      // without loss of precision in general). +      // +      // Also don't accept neither "NAN" nor "INFINITY" (both of which +      // conveniently contain "n"). +      if (strpbrk(s, "xXnN")) +	return NIL; + +      // Disregard optional "f" suffix, it can be just dropped in Python as it +      // uses doubles for everything anyhow. +      for (char * p = end; *p != '\0'; ++p) { +	switch (*p) { +	  case 'f': +	  case 'F': +	    break; + +	  default: +	    return NIL; +	} +      } + +      // Avoid unnecessary string allocation in the common case when we don't +      // need to remove any suffix. +      return *end == '\0' ? Copy(v) : NewStringWithSize(s, (int)(end - s)); +    } + +    return NIL; +  } + +  /* ------------------------------------------------------------ +   * convertValue() +   * +   * Check if string v can be a Python value literal or a +   * constant. Return an equivalent Python representation, +   * or NIL if it isn't, or we are unsure. +   * ------------------------------------------------------------ */ +  String *convertValue(String *v, SwigType *type) { +    const char *const s = Char(v); +    String *result = NIL; +    SwigType *resolved_type = SwigType_typedef_resolve_all(type); + +    result = convertIntegerValue(v, resolved_type); +    if (!result) { +      result = convertDoubleValue(v); +      if (!result) { +	if (Strcmp(v, "true") == 0) +	  result = NewString("True"); +	else if (Strcmp(v, "false") == 0) +	  result = NewString("False"); +	else if (Strcmp(v, "NULL") == 0 || Strcmp(v, "nullptr") == 0) +	  result = SwigType_ispointer(resolved_type) ? NewString("None") : NewString("0"); +	// This could also be an enum type, default value of which could be +	// representable in Python if it doesn't include any scope (which could, +	// but currently is not, translated). +	else if (!Strchr(s, ':')) { +	  Node *lookup = Swig_symbol_clookup(v, 0); +	  if (lookup) { +	    if (Cmp(Getattr(lookup, "nodeType"), "enumitem") == 0) +	      result = Copy(Getattr(lookup, "sym:name")); +	  } +	} +      } +    } + +    Delete(resolved_type); +    return result; +  } + +  /* ------------------------------------------------------------ +   * is_representable_as_pyargs() +   * +   * Check if the function parameters default argument values +   * can be represented in Python. +   * +   * If this method returns false, the parameters will be translated +   * to a generic "*args" which allows us to deal with default values +   * at C++ code level where they can always be handled. +   * ------------------------------------------------------------ */ +  bool is_representable_as_pyargs(Node *n) { +    ParmList *plist = CopyParmList(Getattr(n, "parms")); +    Swig_typemap_attach_parms("default", plist, NULL); + +    Parm *p; +    Parm *pnext; + +    for (p = plist; p; p = pnext) { +      pnext = nextSibling(p); +      String *tm = Getattr(p, "tmap:in"); +      if (tm) { +	Parm *in_next = Getattr(p, "tmap:in:next"); +	if (in_next) +	  pnext = in_next; +	if (checkAttribute(p, "tmap:in:numinputs", "0")) { +	  continue; +	} +      } + +      // "default" typemap can contain arbitrary C++ code, so while it could, in +      // principle, be possible to examine it and check if it's just something +      // simple of the form "$1 = expression" and then use convertValue() to +      // check if expression can be used in Python, but for now we just +      // pessimistically give up and prefer to handle this at C++ level only. +      if (Getattr(p, "tmap:default")) +	return false; + +      String *value = Getattr(p, "value"); +      if (value) { +	String *convertedValue = convertValue(value, Getattr(p, "type")); +	if (!convertedValue) +	  return false; +	Delete(convertedValue); +      } +    } + +    return true; +  } + + +  /* ------------------------------------------------------------ +   * is_real_overloaded() +   * +   * Check if the function is overloaded, but not just have some +   * siblings generated due to the original function having +   * default arguments. +   * ------------------------------------------------------------ */ +  bool is_real_overloaded(Node *n) { +    Node *h = Getattr(n, "sym:overloaded"); +    Node *i; +    if (!h) +      return false; + +    i = Getattr(h, "sym:nextSibling"); +    while (i) { +      Node *nn = Getattr(i, "defaultargs"); +      if (nn != h) { +	/* Check if overloaded function has defaultargs and +	 * pointed to the first overloaded. */ +	return true; +      } +      i = Getattr(i, "sym:nextSibling"); +    } + +    return false; +  } + +  /* ------------------------------------------------------------ +   * make_pyParmList() +   * +   * Generate parameter list for Python functions or methods, +   * reuse make_autodocParmList() to do so. +   * ------------------------------------------------------------ */ +  String *make_pyParmList(Node *n, bool in_class, bool is_calling, int kw, bool has_self_for_count = false) { +    /* Get the original function for a defaultargs copy, +     * see default_arguments() in parser.y. */ +    Node *nn = Getattr(n, "defaultargs"); +    if (nn) +      n = nn; + +    Parm *parms = Getattr(n, "parms"); +    int varargs = parms ? emit_isvarargs(parms) : 0; + +    /* We prefer to explicitly list all parameters of the C function in the +       generated Python code as this makes the function more convenient to use, +       however in some cases we must replace the real parameters list with just +       the catch all "*args". This happens when: + +	1. The function is overloaded as Python doesn't support this. +	2. We were explicitly asked to use the "compact" arguments form. +	3. We were explicitly asked to use default args from C via the "python:cdefaultargs" feature. +	4. One of the default argument values can't be represented in Python. +	5. Varargs that haven't been forced to use a fixed number of arguments with %varargs. +     */ +    if (is_real_overloaded(n) || GetFlag(n, "feature:compactdefaultargs") || GetFlag(n, "feature:python:cdefaultargs") || !is_representable_as_pyargs(n) || varargs) { +      String *parms = NewString(""); +      if (in_class) +	Printf(parms, "self, "); +      Printf(parms, "*args"); +      if (kw) +	Printf(parms, ", **kwargs"); +      return parms; +    } + +    bool funcanno = Equal(Getattr(n, "feature:python:annotations"), "c") ? true : false; +    String *params = NewString(""); +    String *_params = make_autodocParmList(n, false, ((in_class || has_self_for_count)? 2 : 1), is_calling, funcanno); + +    if (in_class) { +      Printf(params, "self"); +      if (Len(_params) > 0) +	Printf(params, ", "); +    } + +    Printv(params, _params, NULL); + +    return params; +  } + +  /* ------------------------------------------------------------ +   * have_pythonprepend() +   * +   * Check if there is a %pythonprepend directive and it has text +   * ------------------------------------------------------------ */ + +  bool have_pythonprepend(Node *n) { +    String *str = Getattr(n, "feature:pythonprepend"); +    return (str && Len(str) > 0); +  } + +  /* ------------------------------------------------------------ +   * pythonprepend() +   * +   * Get the %pythonprepend code, stripping off {} if necessary +   * ------------------------------------------------------------ */ + +  String *pythonprepend(Node *n) { +    String *str = Getattr(n, "feature:pythonprepend"); +    char *t = Char(str); +    if (*t == '{') { +      Delitem(str, 0); +      Delitem(str, DOH_END); +    } +    return str; +  } + +  /* ------------------------------------------------------------ +   * have_pythonappend() +   * +   * Check if there is a %pythonappend directive and it has text +   * ------------------------------------------------------------ */ + +  bool have_pythonappend(Node *n) { +    String *str = Getattr(n, "feature:pythonappend"); +    if (!str) +      str = Getattr(n, "feature:addtofunc"); +    return (str && Len(str) > 0); +  } + +  /* ------------------------------------------------------------ +   * pythonappend() +   * +   * Get the %pythonappend code, stripping off {} if necessary +   * ------------------------------------------------------------ */ + +  String *pythonappend(Node *n) { +    String *str = Getattr(n, "feature:pythonappend"); +    if (!str) +      str = Getattr(n, "feature:addtofunc"); + +    char *t = Char(str); +    if (*t == '{') { +      Delitem(str, 0); +      Delitem(str, DOH_END); +    } +    return str; +  } + +  /* ------------------------------------------------------------ +   * have_addtofunc() +   * +   * Check if there is a %addtofunc directive and it has text +   * ------------------------------------------------------------ */ + +  bool have_addtofunc(Node *n) { +    return have_pythonappend(n) || have_pythonprepend(n); +  } + + +  /* ------------------------------------------------------------ +   * returnTypeAnnotation() +   * +   * Helper function for constructing the function annotation +   * of the returning type, return a empty string for Python 2.x +   * ------------------------------------------------------------ */ +  String *returnTypeAnnotation(Node *n) { +    String *ret = 0; +    Parm *p = Getattr(n, "parms"); +    String *tm; +    /* Try to guess the returning type by argout typemap, +     * however the result may not accurate. */ +    while (p) { +      if ((tm = Getattr(p, "tmap:argout:match_type"))) { +	tm = SwigType_str(tm, 0); +	if (ret) +	  Printv(ret, ", ", tm, NULL); +	else +	  ret = tm; +	p = Getattr(p, "tmap:argout:next"); +      } else { +	p = nextSibling(p); +      } +    } +    /* If no argout typemap, then get the returning type from +     * the function prototype. */ +    if (!ret) { +      ret = Getattr(n, "type"); +      if (ret) +	ret = SwigType_str(ret, 0); +    } +    bool funcanno = Equal(Getattr(n, "feature:python:annotations"), "c") ? true : false; +    return (ret && funcanno) ? NewStringf(" -> \"%s\"", ret) : NewString(""); +  } + +  /* ------------------------------------------------------------ +   * variableAnnotation() +   * +   * Helper function for constructing a variable annotation +   * ------------------------------------------------------------ */ + +  String *variableAnnotation(Node *n) { +    String *type = Getattr(n, "type"); +    if (type) +      type = SwigType_str(type, 0); +    bool anno = Equal(Getattr(n, "feature:python:annotations"), "c") ? true : false; +    anno = GetFlag(n, "feature:python:annotations:novar") ? false : anno; +    String *annotation = (type && anno) ? NewStringf(": \"%s\"", type) : NewString(""); +    Delete(type); +    return annotation; +  } + +  /* ------------------------------------------------------------ +   * emitFunctionShadowHelper() +   * +   * Refactoring some common code out of functionWrapper and +   * dispatchFunction that writes the proxy code for non-member +   * functions. +   * ------------------------------------------------------------ */ + +  void emitFunctionShadowHelper(Node *n, File *f_dest, String *name, int kw) { +    String *parms = make_pyParmList(n, false, false, kw); +    String *callParms = make_pyParmList(n, false, true, kw); + +    // Callbacks need the C function in order to extract the pointer from the swig_ptr: string +    bool fast = (fastproxy && !have_addtofunc(n)) || Getattr(n, "feature:callback"); + +    if (!fast || olddefs) { +      /* Make a wrapper function to insert the code into */ +      Printv(f_dest, "\n", "def ", name, "(", parms, ")", returnTypeAnnotation(n), ":\n", NIL); +      if (have_docstring(n)) +	Printv(f_dest, tab4, docstring(n, AUTODOC_FUNC, tab4, true), "\n", NIL); +      if (have_pythonprepend(n)) +	Printv(f_dest, indent_pythoncode(pythonprepend(n), tab4, Getfile(n), Getline(n), "%pythonprepend or %feature(\"pythonprepend\")"), "\n", NIL); +      if (have_pythonappend(n)) { +	Printv(f_dest, tab4 "val = ", funcCall(name, callParms), "\n", NIL); +	Printv(f_dest, indent_pythoncode(pythonappend(n), tab4, Getfile(n), Getline(n), "%pythonappend or %feature(\"pythonappend\")"), "\n", NIL); +	Printv(f_dest, tab4 "return val\n", NIL); +      } else { +	Printv(f_dest, tab4 "return ", funcCall(name, callParms), "\n", NIL); +      } +    } + +    // Below may result in a 2nd definition of the method when -olddefs is used. The Python interpreter will use the second definition as it overwrites the first. +    if (fast) { +      /* If there is no addtofunc directive then just assign from the extension module (for speed up) */ +      Printv(f_dest, name, " = ", module, ".", name, "\n", NIL); +    } +  } + + +  /* ------------------------------------------------------------ +   * check_kwargs() +   * +   * check if using kwargs is allowed for this Node +   * ------------------------------------------------------------ */ + +  int check_kwargs(Node *n) const { +    return (use_kw || GetFlag(n, "feature:kwargs")) +	&& !GetFlag(n, "memberset") && !GetFlag(n, "memberget"); +  } + + + +  /* ------------------------------------------------------------ +   * add_method() +   * ------------------------------------------------------------ */ + +  void add_method(String *name, String *function, int kw, Node *n = 0, int funpack = 0, int num_required = -1, int num_arguments = -1) { +    String * meth_str = NewString(""); +    if (!kw) { +      if (funpack) { +	if (num_required == 0 && num_arguments == 0) { +	  Printf(meth_str, "\t { \"%s\", %s, METH_NOARGS, ", name, function); +	} else if (num_required == 1 && num_arguments == 1) { +	  Printf(meth_str, "\t { \"%s\", %s, METH_O, ", name, function); +	} else { +	  Printf(meth_str, "\t { \"%s\", %s, METH_VARARGS, ", name, function); +	} +      } else { +	Printf(meth_str, "\t { \"%s\", %s, METH_VARARGS, ", name, function); +      } +    } else { +      // Cast via void(*)(void) to suppress GCC -Wcast-function-type warning. +      // Python should always call the function correctly, but the Python C API +      // requires us to store it in function pointer of a different type. +      Printf(meth_str, "\t { \"%s\", (PyCFunction)(void(*)(void))%s, METH_VARARGS|METH_KEYWORDS, ", name, function); +    } +    Append(methods, meth_str); +    if (fastproxy) { +      Append(methods_proxydocs, meth_str); +    } +    Delete(meth_str); + +    if (!n) { +      Append(methods, "NULL"); +      if (fastproxy) { +	Append(methods_proxydocs, "NULL"); +      } +    } else if (have_docstring(n)) { +      /* Use the low-level docstring here since this is the docstring that will be used for the C API */ +      String *ds = cdocstring(n, Getattr(n, "memberfunction") ? AUTODOC_METHOD : AUTODOC_FUNC, true); +      Printf(methods, "\"%s\"", ds); +      if (fastproxy) { +	/* In the fastproxy case, we must also record the high-level docstring for use in the Python shadow API */ +	Delete(ds); +        ds = cdocstring(n, Getattr(n, "memberfunction") ? AUTODOC_METHOD : AUTODOC_FUNC); +	Printf(methods_proxydocs, "\"%s\"", ds); +      } +      Delete(ds); +    } else if (Getattr(n, "feature:callback")) { +      Printf(methods, "\"swig_ptr: %s\"", Getattr(n, "feature:callback:name")); +      if (fastproxy) { +	Printf(methods_proxydocs, "\"swig_ptr: %s\"", Getattr(n, "feature:callback:name")); +	have_fast_proxy_static_member_method_callback = true; +      } +    } else { +      Append(methods, "NULL"); +      if (fastproxy) { +	Append(methods_proxydocs, "NULL"); +      } +    } + +    Append(methods, "},\n"); +    if (fastproxy) { +      Append(methods_proxydocs, "},\n"); +    } +  } + +  /* ------------------------------------------------------------ +   * dispatchFunction() +   * ------------------------------------------------------------ */ +  void dispatchFunction(Node *n, String *linkage, int funpack = 0, bool builtin_self = false, bool builtin_ctor = false, bool director_class = false, bool use_static_method = false) { +    /* Last node in overloaded chain */ + +    bool add_self = builtin_self && (!builtin_ctor || director_class); + +    int maxargs; + +    String *tmp = NewString(""); +    String *dispatch; + +    const char *dispatch_call = funpack ? "%s(self, argc, argv);" : (builtin_ctor ? "%s(self, args, NULL);" : "%s(self, args);"); +    String *dispatch_code = NewStringf("return %s", dispatch_call); + +    if (castmode) { +      dispatch = Swig_overload_dispatch_cast(n, dispatch_code, &maxargs); +    } else { +      String *fastdispatch_code; +      if (builtin_ctor) +	fastdispatch_code = NewStringf("int retval = %s\nif (retval == 0 || !SWIG_Python_TypeErrorOccurred(NULL)) return retval;\nSWIG_fail;", dispatch_call); +      else +	fastdispatch_code = NewStringf("PyObject *retobj = %s\nif (!SWIG_Python_TypeErrorOccurred(retobj)) return retobj;\nSWIG_fail;", dispatch_call); +      if (!CPlusPlus) { +	Insert(fastdispatch_code, 0, "{\n"); +	Append(fastdispatch_code, "\n}"); +      } +      dispatch = Swig_overload_dispatch(n, dispatch_code, &maxargs, fastdispatch_code); +      Delete(fastdispatch_code); +    } + +    /* Generate a dispatch wrapper for all overloaded functions */ + +    Wrapper *f = NewWrapper(); +    String *symname = Getattr(n, "sym:name"); +    String *wname = Swig_name_wrapper(symname); + +    const char *builtin_kwargs = builtin_ctor ? ", PyObject *kwargs" : ""; +    Printv(f->def, linkage, builtin_ctor ? "int " : "PyObject *", wname, "(PyObject *self, PyObject *args", builtin_kwargs, ") {", NIL); + +    if (builtin) { +      /* Avoid warning if the self parameter is not used. */ +      Append(f->code, "(void)self;\n"); +    } + +    Wrapper_add_local(f, "argc", "Py_ssize_t argc"); +    Printf(tmp, "PyObject *argv[%d] = {0}", maxargs + 1); +    Wrapper_add_local(f, "argv", tmp); + +    if (!fastunpack) { +      Wrapper_add_local(f, "ii", "Py_ssize_t ii"); + +      if (builtin_ctor) +	Printf(f->code, "if (!SWIG_Python_CheckNoKeywords(kwargs, \"%s\")) SWIG_fail;\n", symname); + +      if (maxargs - (add_self ? 1 : 0) > 0) { +        Append(f->code, "if (!PyTuple_Check(args)) SWIG_fail;\n"); +        Append(f->code, "argc = PyObject_Length(args);\n"); +      } else { +        Append(f->code, "argc = args ? PyObject_Length(args) : 0;\n"); +      } + +      if (add_self) +	Append(f->code, "argv[0] = self;\n"); +      Printf(f->code, "for (ii = 0; (ii < %d) && (ii < argc); ii++) {\n", add_self ? maxargs - 1 : maxargs); +      Printf(f->code, "argv[ii%s] = PyTuple_GET_ITEM(args,ii);\n", add_self ? " + 1" : ""); +      Append(f->code, "}\n"); +      if (add_self) +	Append(f->code, "argc++;\n"); +    } else { +      if (builtin_ctor) +	Printf(f->code, "if (!SWIG_Python_CheckNoKeywords(kwargs, \"%s\")) SWIG_fail;\n", symname); +      Printf(f->code, "if (!(argc = SWIG_Python_UnpackTuple(args, \"%s\", 0, %d, argv%s))) SWIG_fail;\n", symname, maxargs, add_self ? "+1" : ""); +      if (add_self) +	Append(f->code, "argv[0] = self;\n"); +      else +	Append(f->code, "--argc;\n"); +    } + +    Replaceall(dispatch, "$args", "self, args"); + +    Printv(f->code, dispatch, "\n", NIL); + +    if (GetFlag(n, "feature:python:maybecall")) { +      Append(f->code, "fail:\n"); +      Append(f->code, "  Py_INCREF(Py_NotImplemented);\n"); +      Append(f->code, "  return Py_NotImplemented;\n"); +    } else { +      Node *sibl = n; +      while (Getattr(sibl, "sym:previousSibling")) +	sibl = Getattr(sibl, "sym:previousSibling");	// go all the way up +      String *protoTypes = NewString(""); +      do { +	String *fulldecl = Swig_name_decl(sibl); +	Printf(protoTypes, "\n\"    %s\\n\"", fulldecl); +	Delete(fulldecl); +      } while ((sibl = Getattr(sibl, "sym:nextSibling"))); +      Append(f->code, "fail:\n"); +      Printf(f->code, "  SWIG_Python_RaiseOrModifyTypeError(" +	     "\"Wrong number or type of arguments for overloaded function '%s'.\\n\"" "\n\"  Possible C/C++ prototypes are:\\n\"%s);\n", symname, protoTypes); +      Printf(f->code, "return %s;\n", builtin_ctor ? "-1" : "0"); +      Delete(protoTypes); +    } +    Printv(f->code, "}\n", NIL); +    Wrapper_print(f, f_wrappers); +    Node *p = Getattr(n, "sym:previousSibling"); +    if (!builtin_self && (use_static_method || !builtin)) +      add_method(symname, wname, 0, p); + +    /* Create a shadow for this function (if enabled and not in a member function) */ +    if (!builtin && shadow && !(shadow & PYSHADOW_MEMBER) && use_static_method) { +      emitFunctionShadowHelper(n, in_class ? f_shadow_stubs : f_shadow, symname, 0); +    } +    DelWrapper(f); +    Delete(dispatch); +    Delete(dispatch_code); +    Delete(tmp); +    Delete(wname); +  } + +  /* ------------------------------------------------------------ +   * functionWrapper() +   * ------------------------------------------------------------ */ + +  /* +    A note about argument marshalling with built-in types. +    There are three distinct cases for member (non-static) methods: + +    1) An ordinary member function.  In this case, the first param in +    the param list is 'this'.  For builtin types, 'this' is taken from +    the first argument to the wrapper (usually called 'self); it's not +    extracted from the second argument (which is usually a tuple). + +    2) A constructor for a non-director class.  In this case, the +    param list doesn't contain an entry for 'this', but the first ('self') +    argument to the wrapper *does* contain the newly-allocated, +    uninitialized object. + +    3) A constructor for a director class.  In this case, the param +    list contains a 'self' param, which comes from the first argument +    to the wrapper function. +  */ + +  const char *get_implicitconv_flag(Node *klass) { +    int conv = 0; +    if (klass && GetFlag(klass, "feature:implicitconv")) { +      conv = 1; +    } +    return conv ? "SWIG_POINTER_IMPLICIT_CONV" : "0"; +  } + + +  virtual int functionWrapper(Node *n) { + +    String *name = Getattr(n, "name"); +    String *iname = Getattr(n, "sym:name"); +    SwigType *d = Getattr(n, "type"); +    ParmList *l = Getattr(n, "parms"); +    Node *parent = Swig_methodclass(n); + +    int director_method = 0; + +    Parm *p; +    int i; +    char source[64]; +    Wrapper *f; +    String *self_parse; +    String *parse_args; +    String *arglist; +    String *get_pointers; +    String *cleanup; +    String *outarg; +    String *kwargs; +    String *tm; +    String *overname = 0; + +    int num_required; +    int num_arguments; +    int num_fixed_arguments; +    int tuple_required; +    int tuple_arguments; +    int varargs = 0; +    int allow_kwargs = check_kwargs(n); + +    String *nodeType = Getattr(n, "nodeType"); +    int constructor = (!Cmp(nodeType, "constructor")); +    int destructor = (!Cmp(nodeType, "destructor")); +    String *storage = Getattr(n, "storage"); +    /* Only the first constructor is handled as init method. Others +       constructor can be emitted via %rename */ +    int handled_as_init = 0; +    if (!have_constructor && (constructor || Getattr(n, "handled_as_constructor")) +	&& ((shadow & PYSHADOW_MEMBER))) { +      String *nname = Getattr(n, "sym:name"); +      String *sname = Getattr(getCurrentClass(), "sym:name"); +      String *cname = Swig_name_construct(NSPACE_TODO, sname); +      handled_as_init = (Strcmp(nname, sname) == 0) || (Strcmp(nname, cname) == 0); +      Delete(cname); +    } +    bool builtin_self = builtin && in_class && (constructor || (l && Getattr(l, "self"))); +    bool builtin_ctor = false; +    if (builtin_self && constructor) { +      String *class_mname = Getattr(getCurrentClass(), "sym:name"); +      String *mrename = Swig_name_construct(getNSpace(), class_mname); +      if (Cmp(iname, mrename)) +	builtin_self = false; +      else +	builtin_ctor = true; +      Delete(mrename); +    } +    bool director_class = (getCurrentClass() && Swig_directorclass(getCurrentClass())); +    bool add_self = builtin_self && (!builtin_ctor || director_class); +    bool builtin_getter = (builtin && GetFlag(n, "memberget")); +    bool builtin_setter = (builtin && GetFlag(n, "memberset") && !builtin_getter); +    char const *wrap_return = builtin_ctor ? "int " : "PyObject *"; +    String *linkage = NewString("SWIGINTERN "); +    String *wrapper_name = Swig_name_wrapper(iname); + +    if (Getattr(n, "sym:overloaded")) { +      overname = Getattr(n, "sym:overname"); +    } else { +      if (!addSymbol(iname, n)) +	return SWIG_ERROR; +    } + +    f = NewWrapper(); +    self_parse = NewString(""); +    parse_args = NewString(""); +    arglist = NewString(""); +    get_pointers = NewString(""); +    cleanup = NewString(""); +    outarg = NewString(""); +    kwargs = NewString(""); + +    int allow_thread = threads_enable(n); + +    Wrapper_add_local(f, "resultobj", "PyObject *resultobj = 0"); + +    // Emit all of the local variables for holding arguments. +    emit_parameter_variables(l, f); + +    /* Attach the standard typemaps */ +    emit_attach_parmmaps(l, f); +    Setattr(n, "wrap:parms", l); +    /* Get number of required and total arguments */ +    tuple_arguments = num_arguments = emit_num_arguments(l); +    tuple_required = num_required = emit_num_required(l); +    if (add_self) { +      --tuple_arguments; +      --tuple_required; +    } +    num_fixed_arguments = tuple_required; + +    // builtin handles/checks kwargs by default except in constructor wrappers so we need to explicitly handle them in the C constructor wrapper +    // The check below is for zero arguments. Sometimes (eg directors) self is the first argument for a method with zero arguments. +    if (((num_arguments == 0) && (num_required == 0)) || ((num_arguments == 1) && (num_required == 1) && Getattr(l, "self"))) +      if (!builtin_ctor) +	allow_kwargs = 0; +    varargs = emit_isvarargs(l); + +    String *wname = Copy(wrapper_name); +    if (overname) { +      Append(wname, overname); +    } + +    const char *builtin_kwargs = builtin_ctor ? ", PyObject *kwargs" : ""; +    if (!allow_kwargs || overname) { +      if (!varargs) { +	Printv(f->def, linkage, wrap_return, wname, "(PyObject *self, PyObject *args", builtin_kwargs, ") {", NIL); +      } else { +	Printv(f->def, linkage, wrap_return, wname, "__varargs__", "(PyObject *self, PyObject *args, PyObject *varargs", builtin_kwargs, ") {", NIL); +      } +      if (allow_kwargs) { +	Swig_warning(WARN_LANG_OVERLOAD_KEYWORD, input_file, line_number, "Can't use keyword arguments with overloaded functions (%s).\n", Swig_name_decl(n)); +	allow_kwargs = 0; +      } +    } else { +      if (varargs) { +	Swig_warning(WARN_LANG_VARARGS_KEYWORD, input_file, line_number, "Can't wrap varargs with keyword arguments enabled\n"); +	varargs = 0; +      } +      Printv(f->def, linkage, wrap_return, wname, "(PyObject *self, PyObject *args, PyObject *kwargs) {", NIL); +      /* Avoid warning if the self parameter is not used. */ +      Append(f->def, "(void)self;\n"); +    } + +    if (builtin) { +      /* Avoid warning if the self parameter is not used. */ +      Append(f->code, "(void)self;\n"); +    } + +    if (!builtin || !in_class || tuple_arguments > 0 || builtin_ctor) { +      if (!allow_kwargs) { +	Append(parse_args, "    if (!PyArg_ParseTuple(args, \""); +      } else { +	Append(parse_args, "    if (!PyArg_ParseTupleAndKeywords(args, kwargs, \""); +	Append(arglist, ", kwnames"); +      } +    } + +    bool over_varargs = emit_isvarargs_function(n); + +    int funpack = fastunpack && !varargs && !over_varargs && !allow_kwargs; +    int noargs = funpack && (tuple_required == 0 && tuple_arguments == 0); +    int onearg = funpack && (tuple_required == 1 && tuple_arguments == 1); + +    if (builtin && funpack && !overname && !builtin_ctor) { +      int compactdefargs = ParmList_is_compactdefargs(l); +      if (!(compactdefargs && (tuple_arguments > tuple_required || varargs))) { +	String *argattr = NewStringf("%d", tuple_arguments); +	Setattr(n, "python:argcount", argattr); +	Delete(argattr); +      } +    } + +    /* Generate code for argument marshalling */ +    if (funpack) { +      if (num_arguments > (builtin_self && !constructor ? 1 : 0) && !overname) { +	sprintf(source, "PyObject *swig_obj[%d]", num_arguments); +	Wrapper_add_localv(f, "swig_obj", source, NIL); +      } +    } + + +    if (constructor && num_arguments == 1 && num_required == 1) { +      if (Cmp(storage, "explicit") == 0) { +	if (GetFlag(parent, "feature:implicitconv")) { +	  String *desc = NewStringf("SWIGTYPE%s", SwigType_manglestr(Getattr(n, "type"))); +	  Printf(f->code, "if (SWIG_CheckImplicit(%s)) SWIG_fail;\n", desc); +	  Delete(desc); +	} +      } +    } + +    if (builtin_ctor && checkAttribute(n, "access", "protected")) { +      String *tmp_none_comparison = Copy(none_comparison); +      Replaceall(tmp_none_comparison, "$arg", "self"); +      Printf(self_parse, "if (!(%s)) {\n", tmp_none_comparison); +      Printv(self_parse, "  SWIG_SetErrorMsg(PyExc_RuntimeError, \"accessing abstract class or protected constructor\");\n  SWIG_fail;\n}\n", NIL); +      Delete(tmp_none_comparison); +    } + +    int use_parse = 0; +    Append(kwargs, "{"); +    for (i = 0, p = l; i < num_arguments; i++) { +      while (checkAttribute(p, "tmap:in:numinputs", "0")) { +	p = Getattr(p, "tmap:in:next"); +      } + +      SwigType *pt = Getattr(p, "type"); +      String *ln = Getattr(p, "lname"); +      bool parse_from_tuple = (i > 0 || !add_self); +      if (SwigType_type(pt) == T_VARARGS) { +	parse_from_tuple = false; +	num_fixed_arguments -= atoi(Char(Getattr(p, "tmap:in:numinputs"))); +      } +      if (!parse_from_tuple) +	sprintf(source, "self"); +      else if (funpack) +	sprintf(source, "swig_obj[%d]", add_self && !overname ? i - 1 : i); +      else +	sprintf(source, "obj%d", builtin_ctor ? i + 1 : i); + +      if (parse_from_tuple) { +	Printf(arglist, ", "); +	if (i == num_required) +	  Putc('|', parse_args);	/* Optional argument separator */ +      } + +      /* Keyword argument handling */ +      if (allow_kwargs && parse_from_tuple) { +	String *name = makeParameterName(n, p, i + 1); +	Printf(kwargs, " (char *)\"%s\", ", name); +	Delete(name); +      } + +      /* Look for an input typemap */ +      if ((tm = Getattr(p, "tmap:in"))) { +	String *parse = Getattr(p, "tmap:in:parse"); +	if (!parse) { +	  if (builtin_self) { +	    Replaceall(tm, "$self", "self"); +	  } else if (funpack) { +	    Replaceall(tm, "$self", "swig_obj[0]"); +	  } else { +	    Replaceall(tm, "$self", "obj0"); +	  } +	  Replaceall(tm, "$input", source); +	  Setattr(p, "emit:input", source);	/* Save the location of the object */ + +	  if (Getattr(p, "wrap:disown") || (Getattr(p, "tmap:in:disown"))) { +	    Replaceall(tm, "$disown", "SWIG_POINTER_DISOWN"); +	  } else { +	    Replaceall(tm, "$disown", "0"); +	  } + +	  if (Getattr(p, "tmap:in:implicitconv")) { +	    const char *convflag = "0"; +	    if (!Getattr(p, "hidden")) { +	      SwigType *ptype = Getattr(p, "type"); +	      convflag = get_implicitconv_flag(classLookup(ptype)); +	    } +	    Replaceall(tm, "$implicitconv", convflag); +	    Setattr(p, "implicitconv", convflag); +	  } + +	  if (parse_from_tuple) +	    Putc('O', parse_args); +	  if (!funpack && parse_from_tuple) { +	    Wrapper_add_localv(f, source, "PyObject *", source, "= 0", NIL); +	    Printf(arglist, "&%s", source); +	  } +	  if (i >= num_required) +	    Printv(get_pointers, "if (", source, ") {\n", NIL); +	  Printv(get_pointers, tm, "\n", NIL); +	  if (i >= num_required) +	    Printv(get_pointers, "}\n", NIL); + +	} else { +	  use_parse = 1; +	  Append(parse_args, parse); +	  if (parse_from_tuple) +	    Printf(arglist, "&%s", ln); +	} +	p = Getattr(p, "tmap:in:next"); +	continue; +      } else { +	Swig_warning(WARN_TYPEMAP_IN_UNDEF, input_file, line_number, "Unable to use type %s as a function argument.\n", SwigType_str(pt, 0)); +	break; +      } +    } + +    /* finish argument marshalling */ +    Append(kwargs, " NULL }"); +    if (allow_kwargs) { +      Printv(f->locals, "  char * kwnames[] = ", kwargs, ";\n", NIL); +    } + +    if (use_parse || allow_kwargs) { +      Printf(parse_args, ":%s\"", iname); +      Printv(parse_args, arglist, ")) SWIG_fail;\n", NIL); +      funpack = 0; +    } else { +      Clear(parse_args); + +      if (funpack) { +	Clear(f->def); +	if (overname) { +	  if (noargs) { +	    Printv(f->def, linkage, wrap_return, wname, "(PyObject *self, Py_ssize_t nobjs, PyObject **SWIGUNUSEDPARM(swig_obj)) {", NIL); +	  } else { +	    Printv(f->def, linkage, wrap_return, wname, "(PyObject *self, Py_ssize_t nobjs, PyObject **swig_obj) {", NIL); +	  } +	  /* Avoid warning if the self parameter is not used. */ +	  Append(f->def, "(void)self;\n"); +	  Printf(parse_args, "if ((nobjs < %d) || (nobjs > %d)) SWIG_fail;\n", num_required, num_arguments); +	} else { +	  int is_tp_call = Equal(Getattr(n, "feature:python:slot"), "tp_call"); +	  Printv(f->def, linkage, wrap_return, wname, "(PyObject *self, PyObject *args", builtin_kwargs, ") {", NIL); +	  /* Avoid warning if the self parameter is not used. */ +	  Append(f->def, "(void)self;\n"); +	  if (builtin_ctor) +	    Printf(parse_args, "if (!SWIG_Python_CheckNoKeywords(kwargs, \"%s\")) SWIG_fail;\n", iname); +	  if (onearg && !builtin_ctor && !is_tp_call) { +	    Printf(parse_args, "if (!args) SWIG_fail;\n"); +	    Append(parse_args, "swig_obj[0] = args;\n"); +	  } else if (!noargs) { +	    Printf(parse_args, "if (!SWIG_Python_UnpackTuple(args, \"%s\", %d, %d, swig_obj)) SWIG_fail;\n", iname, num_fixed_arguments, tuple_arguments); +	  } else if (noargs) { +	    Printf(parse_args, "if (!SWIG_Python_UnpackTuple(args, \"%s\", %d, %d, 0)) SWIG_fail;\n", iname, num_fixed_arguments, tuple_arguments); +	  } +	} +      } else { +	if (builtin_ctor) +	  Printf(parse_args, "if (!SWIG_Python_CheckNoKeywords(kwargs, \"%s\")) SWIG_fail;\n", iname); +	if (builtin && in_class && tuple_arguments == 0) { +	  Printf(parse_args, "    if (args && PyTuple_Check(args) && PyTuple_GET_SIZE(args) > 0) SWIG_exception_fail(SWIG_TypeError, \"%s takes no arguments\");\n", iname); +	} else { +	  Printf(parse_args, "if (!PyArg_UnpackTuple(args, \"%s\", %d, %d", iname, num_fixed_arguments, tuple_arguments); +	  Printv(parse_args, arglist, ")) SWIG_fail;\n", NIL); +	} +      } +    } + +    /* Now piece together the first part of the wrapper function */ +    Printv(f->code, self_parse, parse_args, get_pointers, NIL); + +    /* Check for trailing varargs */ +    if (varargs) { +      if (p && (tm = Getattr(p, "tmap:in"))) { +	Replaceall(tm, "$input", "varargs"); +	Printv(f->code, tm, "\n", NIL); +      } +    } + +    /* Insert constraint checking code */ +    for (p = l; p;) { +      if ((tm = Getattr(p, "tmap:check"))) { +	Printv(f->code, tm, "\n", NIL); +	p = Getattr(p, "tmap:check:next"); +      } else { +	p = nextSibling(p); +      } +    } + +    /* Insert cleanup code */ +    for (p = l; p;) { +      if (!Getattr(p, "tmap:in:parse") && (tm = Getattr(p, "tmap:freearg"))) { +	if (Getattr(p, "tmap:freearg:implicitconv")) { +	  const char *convflag = "0"; +	  if (!Getattr(p, "hidden")) { +	    SwigType *ptype = Getattr(p, "type"); +	    convflag = get_implicitconv_flag(classLookup(ptype)); +	  } +	  if (strcmp(convflag, "0") == 0) { +	    tm = 0; +	  } +	} +	if (tm && (Len(tm) != 0)) { +	  Printv(cleanup, tm, "\n", NIL); +	} +	p = Getattr(p, "tmap:freearg:next"); +      } else { +	p = nextSibling(p); +      } +    } + +    /* Insert argument output code */ +    for (p = l; p;) { +      if ((tm = Getattr(p, "tmap:argout"))) { +	Replaceall(tm, "$arg", Getattr(p, "emit:input")); +	Replaceall(tm, "$input", Getattr(p, "emit:input")); +	Printv(outarg, tm, "\n", NIL); +	p = Getattr(p, "tmap:argout:next"); +      } else { +	p = nextSibling(p); +      } +    } + +    /* if the object is a director, and the method call originated from its +     * underlying python object, resolve the call by going up the c++ +     * inheritance chain.  otherwise try to resolve the method in python. +     * without this check an infinite loop is set up between the director and +     * shadow class method calls. +     */ + +    // NOTE: this code should only be inserted if this class is the +    // base class of a director class.  however, in general we haven't +    // yet analyzed all classes derived from this one to see if they are +    // directors.  furthermore, this class may be used as the base of +    // a director class defined in a completely different module at a +    // later time, so this test must be included whether or not directorbase +    // is true.  we do skip this code if directors have not been enabled +    // at the command line to preserve source-level compatibility with +    // non-polymorphic swig.  also, if this wrapper is for a smart-pointer +    // method, there is no need to perform the test since the calling object +    // (the smart-pointer) and the director object (the "pointee") are +    // distinct. + +    director_method = is_member_director(n) && !is_smart_pointer() && !destructor; +    if (director_method) { +      Wrapper_add_local(f, "director", "Swig::Director *director = 0"); +      Append(f->code, "director = SWIG_DIRECTOR_CAST(arg1);\n"); +      if (dirprot_mode() && !is_public(n)) { +	Printf(f->code, "if (!director || !(director->swig_get_inner(\"%s\"))) {\n", name); +	Printf(f->code, "SWIG_SetErrorMsg(PyExc_RuntimeError,\"accessing protected member %s\");\n", name); +	Append(f->code, "SWIG_fail;\n"); +	Append(f->code, "}\n"); +      } +      Wrapper_add_local(f, "upcall", "bool upcall = false"); +      if (funpack) { +	const char *self_parm = builtin_self ? "self" : "swig_obj[0]"; +	Printf(f->code, "upcall = (director && (director->swig_get_self()==%s));\n", self_parm); +      } else { +	const char *self_parm = builtin_self ? "self" : "obj0"; +	Printf(f->code, "upcall = (director && (director->swig_get_self()==%s));\n", self_parm); +      } +    } + +    /* Emit the function call */ +    if (director_method) { +      Append(f->code, "try {\n"); +    } else { +      if (allow_thread) { +	String *preaction = NewString(""); +	thread_begin_allow(n, preaction); +	Setattr(n, "wrap:preaction", preaction); + +	String *postaction = NewString(""); +	thread_end_allow(n, postaction); +	Setattr(n, "wrap:postaction", postaction); +      } +    } + +    Setattr(n, "wrap:name", wname); + +    Swig_director_emit_dynamic_cast(n, f); +    String *actioncode = emit_action(n); + +    if (director_method) { +      Append(actioncode, "} catch (Swig::DirectorException&) {\n"); +      Append(actioncode, "  SWIG_fail;\n"); +      Append(actioncode, "}\n"); +    } + +    /* This part below still needs cleanup */ + +    /* Return the function value */ +    tm = Swig_typemap_lookup_out("out", n, Swig_cresult_name(), f, actioncode); + +    if (tm) { +      if (builtin_self) { +	Replaceall(tm, "$self", "self"); +      } else if (funpack) { +	Replaceall(tm, "$self", "swig_obj[0]"); +      } else { +	Replaceall(tm, "$self", "obj0"); +      } +      Replaceall(tm, "$result", "resultobj"); +      if (builtin_ctor) { +	Replaceall(tm, "$owner", "SWIG_BUILTIN_INIT"); +      } else if (handled_as_init) { +	Replaceall(tm, "$owner", "SWIG_POINTER_NEW"); +      } else { +	if (GetFlag(n, "feature:new")) { +	  Replaceall(tm, "$owner", "SWIG_POINTER_OWN"); +	} else { +	  Replaceall(tm, "$owner", "0"); +	} +      } + +      // Unwrap return values that are director classes so that the original Python object is returned instead.  +      if (!constructor && Swig_director_can_unwrap(n)) { +	Wrapper_add_local(f, "director", "Swig::Director *director = 0"); +	Printf(f->code, "director = SWIG_DIRECTOR_CAST(%s);\n", Swig_cresult_name()); +	Append(f->code, "if (director) {\n"); +	Append(f->code, "  resultobj = director->swig_get_self();\n"); +	Append(f->code, "  Py_INCREF(resultobj);\n"); +	Append(f->code, "} else {\n"); +	Printf(f->code, "%s\n", tm); +	Append(f->code, "}\n"); +      } else { +	Printf(f->code, "%s\n", tm); +      } + +      Delete(tm); +    } else { +      Swig_warning(WARN_TYPEMAP_OUT_UNDEF, input_file, line_number, "Unable to use return type %s in function %s.\n", SwigType_str(d, 0), name); +    } +    emit_return_variable(n, d, f); + +    /* Output argument output code */ +    Printv(f->code, outarg, NIL); + +    /* Output cleanup code */ +    int need_cleanup = Len(cleanup) != 0; +    if (need_cleanup) { +      Printv(f->code, cleanup, NIL); +    } + +    /* Look to see if there is any newfree cleanup code */ +    if (GetFlag(n, "feature:new")) { +      if ((tm = Swig_typemap_lookup("newfree", n, Swig_cresult_name(), 0))) { +	Printf(f->code, "%s\n", tm); +	Delete(tm); +      } +    } + +    /* See if there is any return cleanup code */ +    if ((tm = Swig_typemap_lookup("ret", n, Swig_cresult_name(), 0))) { +      Printf(f->code, "%s\n", tm); +      Delete(tm); +    } + +    if (director_method) { +      if ((tm = Swig_typemap_lookup("directorfree", n, Swig_cresult_name(), 0))) { +	Replaceall(tm, "$input", Swig_cresult_name()); +	Replaceall(tm, "$result", "resultobj"); +	Printf(f->code, "%s\n", tm); +	Delete(tm); +      } +    } + +    if (builtin_ctor) +      Append(f->code, "    return resultobj == Py_None ? -1 : 0;\n"); +    else +      Append(f->code, "    return resultobj;\n"); + +    /* Error handling code */ + +    Append(f->code, "fail:\n"); +    if (need_cleanup) { +      Printv(f->code, cleanup, NIL); +    } +    if (builtin_ctor) { +      Printv(f->code, "  return -1;\n", NIL); +    } else { +      if (GetFlag(n, "feature:python:maybecall")) { +	Append(f->code, "  PyErr_Clear();\n"); +	Append(f->code, "  Py_INCREF(Py_NotImplemented);\n"); +	Append(f->code, "  return Py_NotImplemented;\n"); +      } else { +        Printv(f->code, "  return NULL;\n", NIL); +      } +    } + +    Append(f->code, "}\n"); + +    /* Substitute the cleanup code */ +    Replaceall(f->code, "$cleanup", cleanup); + +    /* Substitute the function name */ +    Replaceall(f->code, "$symname", iname); +    Replaceall(f->code, "$result", "resultobj"); + +    if (builtin_self) { +      Replaceall(f->code, "$self", "self"); +    } else if (funpack) { +      Replaceall(f->code, "$self", "swig_obj[0]"); +    } else { +      Replaceall(f->code, "$self", "obj0"); +    } + +    /* Dump the function out */ +    Wrapper_print(f, f_wrappers); + +    /* If varargs.  Need to emit a varargs stub */ +    if (varargs) { +      DelWrapper(f); +      f = NewWrapper(); +      if (funpack) { +	// Note: funpack is currently always false for varargs +	Printv(f->def, linkage, wrap_return, wname, "(PyObject *self, Py_ssize_t nobjs, PyObject **swig_obj) {", NIL); +      } else { +	Printv(f->def, linkage, wrap_return, wname, "(PyObject *self, PyObject *args", builtin_kwargs, ") {", NIL); +      } +      Wrapper_add_local(f, "resultobj", builtin_ctor ? "int resultobj" : "PyObject *resultobj"); +      Wrapper_add_local(f, "varargs", "PyObject *varargs"); +      Wrapper_add_local(f, "newargs", "PyObject *newargs"); +      if (funpack) { +	Wrapper_add_local(f, "i", "int i"); +	Printf(f->code, "newargs = PyTuple_New(%d);\n", num_fixed_arguments); +	Printf(f->code, "for (i = 0; i < %d; ++i) {\n", num_fixed_arguments); +	Printf(f->code, "  PyTuple_SET_ITEM(newargs, i, swig_obj[i]);\n"); +	Printf(f->code, "  Py_XINCREF(swig_obj[i]);\n"); +	Printf(f->code, "}\n"); +	Printf(f->code, "varargs = PyTuple_New(nobjs > %d ? nobjs - %d : 0);\n", num_fixed_arguments, num_fixed_arguments); +	Printf(f->code, "for (i = 0; i < nobjs - %d; ++i) {\n", num_fixed_arguments); +	Printf(f->code, "  PyTuple_SET_ITEM(newargs, i, swig_obj[i + %d]);\n", num_fixed_arguments); +	Printf(f->code, "  Py_XINCREF(swig_obj[i + %d]);\n", num_fixed_arguments); +	Printf(f->code, "}\n"); +      } else { +	Printf(f->code, "newargs = PyTuple_GetSlice(args, 0, %d);\n", num_fixed_arguments); +	Printf(f->code, "varargs = PyTuple_GetSlice(args, %d, PyTuple_Size(args));\n", num_fixed_arguments); +      } +      Printf(f->code, "resultobj = %s__varargs__(%s, newargs, varargs%s);\n", wname, builtin ? "self" : "NULL", strlen(builtin_kwargs) == 0 ? "" : ", kwargs"); +      Append(f->code, "Py_XDECREF(newargs);\n"); +      Append(f->code, "Py_XDECREF(varargs);\n"); +      Append(f->code, "return resultobj;\n"); +      Append(f->code, "}\n"); +      Wrapper_print(f, f_wrappers); +    } + +    bool use_static_method = flat_static_method || !Swig_storage_isstatic_custom(n, "staticmemberfunctionHandler:storage"); +    /* Now register the function with the interpreter.   */ +    if (!Getattr(n, "sym:overloaded")) { +      if (!builtin_self && (use_static_method || !builtin)) +	add_method(iname, wname, allow_kwargs, n, funpack, num_required, num_arguments); + +      /* Create a shadow for this function (if enabled and not in a member function) */ +      if (!builtin && shadow && !(shadow & PYSHADOW_MEMBER) && use_static_method) { +	emitFunctionShadowHelper(n, in_class ? f_shadow_stubs : f_shadow, iname, allow_kwargs); +      } + +    } else { +      if (!Getattr(n, "sym:nextSibling")) { +	dispatchFunction(n, linkage, funpack, builtin_self, builtin_ctor, director_class, use_static_method); +      } +    } + +    // Put this in tp_init of the PyTypeObject +    if (builtin_ctor) { +      if ((director_method || !is_private(n)) && !Getattr(class_members, iname)) { +	Setattr(class_members, iname, n); +	if (!builtin_tp_init) +	  builtin_tp_init = Swig_name_wrapper(iname); +      } +    } + +    /* If this is a builtin type, create a PyGetSetDef entry for this member variable. */ +    if (builtin) { +      const char *memname = "__dict__"; +      Hash *h = Getattr(builtin_getset, memname); +      if (!h) { +        h = NewHash(); +        Setattr(builtin_getset, memname, h); +        Delete(h); +      } +      Setattr(h, "getter", "SwigPyObject_get___dict__"); +      if (!Getattr(h, "doc")) { +	Setattr(n, "doc:high:name", Getattr(n, "name")); +	Setattr(h, "doc", cdocstring(n, AUTODOC_VAR)); +      } +    } + +    if (builtin_getter) { +      String *memname = Getattr(n, "membervariableHandler:sym:name"); +      if (!memname) +	memname = iname; +      Hash *h = Getattr(builtin_getset, memname); +      if (!h) { +	h = NewHash(); +	Setattr(builtin_getset, memname, h); +	Delete(h); +      } +      Setattr(h, "getter", wrapper_name); +      Delattr(n, "memberget"); +      if (!Getattr(h, "doc")) { +	Setattr(n, "doc:high:name", Getattr(n, "name")); +	String *ds = cdocstring(n, AUTODOC_VAR); +	Setattr(h, "doc", ds); +	Delete(ds); +      } +    } +    if (builtin_setter) { +      String *memname = Getattr(n, "membervariableHandler:sym:name"); +      if (!memname) +	memname = iname; +      Hash *h = Getattr(builtin_getset, memname); +      if (!h) { +	h = NewHash(); +	Setattr(builtin_getset, memname, h); +	Delete(h); +      } +      Setattr(h, "setter", wrapper_name); +      Delattr(n, "memberset"); +      if (!Getattr(h, "doc")) { +	Setattr(n, "doc:high:name", Getattr(n, "name")); +	String *ds = cdocstring(n, AUTODOC_VAR); +	Setattr(h, "doc", ds); +	Delete(ds); +      } +    } + +    if (in_class && builtin) { +      /* Handle operator overloads for builtin types */ +      String *slot = Getattr(n, "feature:python:slot"); +      if (slot) { +	String *func_type = Getattr(n, "feature:python:slot:functype"); +	String *closure_decl = getClosure(func_type, wrapper_name, overname ? 0 : funpack); +	String *feature_name = NewStringf("feature:python:%s", slot); +	String *closure_name = 0; +	if (closure_decl) { +	  closure_name = NewStringf("%s_%s_closure", wrapper_name, func_type); +	  if (!GetFlag(builtin_closures, closure_name)) +	    Printf(builtin_closures_code, "%s /* defines %s */\n\n", closure_decl, closure_name); +	  SetFlag(builtin_closures, closure_name); +	  Delete(closure_decl); +	} else { +	  closure_name = Copy(wrapper_name); +	} +	if (func_type) { +	  String *s = NewStringf("%s", closure_name); +	  Delete(closure_name); +	  closure_name = s; +	} +	Setattr(parent, feature_name, closure_name); +	Delete(feature_name); +	Delete(closure_name); +      } + +      /* Handle comparison operators for builtin types */ +      String *compare = Getattr(n, "feature:python:compare"); +      if (compare) { +	Hash *richcompare = Getattr(parent, "python:richcompare"); +	assert(richcompare); +	Setattr(richcompare, compare, wrapper_name); +      } +    } + +    Delete(self_parse); +    Delete(parse_args); +    Delete(linkage); +    Delete(arglist); +    Delete(get_pointers); +    Delete(cleanup); +    Delete(outarg); +    Delete(kwargs); +    Delete(wname); +    DelWrapper(f); +    Delete(wrapper_name); +    return SWIG_OK; +  } + + + +  /* ------------------------------------------------------------ +   * variableWrapper() +   * ------------------------------------------------------------ */ + +  virtual int variableWrapper(Node *n) { +    String *name = Getattr(n, "name"); +    String *iname = Getattr(n, "sym:name"); +    SwigType *t = Getattr(n, "type"); + +    static int have_globals = 0; +    String *tm; +    Wrapper *getf, *setf; + +    if (!addSymbol(iname, n)) +      return SWIG_ERROR; + +    getf = NewWrapper(); +    setf = NewWrapper(); + +    /* If this is our first call, add the globals variable to the +       Python dictionary. */ + +    if (!have_globals) { +      Printf(f_init, "\t globals = SWIG_globals();\n"); +      Printf(f_init, "\t if (!globals) {\n"); +      Printf(f_init, "     PyErr_SetString(PyExc_TypeError, \"Failure to create SWIG globals.\");\n"); +      Printf(f_init, "#if PY_VERSION_HEX >= 0x03000000\n"); +      Printf(f_init, "\t   return NULL;\n"); +      Printf(f_init, "#else\n"); +      Printf(f_init, "\t   return;\n"); +      Printf(f_init, "#endif\n"); +      Printf(f_init, "\t }\n"); +      Printf(f_init, "\t PyDict_SetItemString(md, \"%s\", globals);\n", global_name); +      if (builtin) +	Printf(f_init, "\t SwigPyBuiltin_AddPublicSymbol(public_interface, \"%s\");\n", global_name); +      have_globals = 1; +      if (!builtin && shadow && !(shadow & PYSHADOW_MEMBER)) { +	Printf(f_shadow_stubs, "%s = %s.%s\n", global_name, module, global_name); +      } +    } +    int assignable = is_assignable(n); + +    if (!builtin && shadow && !assignable && !in_class) +      Printf(f_shadow_stubs, "%s = %s.%s\n", iname, global_name, iname); + +    String *getname = Swig_name_get(NSPACE_TODO, iname); +    String *setname = Swig_name_set(NSPACE_TODO, iname); +    String *vargetname = NewStringf("Swig_var_%s", getname); +    String *varsetname = NewStringf("Swig_var_%s", setname); + +    /* Create a function for setting the value of the variable */ +    if (assignable) { +      Setattr(n, "wrap:name", varsetname); +      if (builtin && in_class) { +	String *set_wrapper = Swig_name_wrapper(setname); +	Setattr(n, "pybuiltin:setter", set_wrapper); +	Delete(set_wrapper); +      } +      Printf(setf->def, "SWIGINTERN int %s(PyObject *_val) {", varsetname); +      if ((tm = Swig_typemap_lookup("varin", n, name, 0))) { +	Replaceall(tm, "$input", "_val"); +	if (Getattr(n, "tmap:varin:implicitconv")) { +	  Replaceall(tm, "$implicitconv", get_implicitconv_flag(n)); +	} +	emit_action_code(n, setf->code, tm); +	Delete(tm); +      } else { +	Swig_warning(WARN_TYPEMAP_VARIN_UNDEF, input_file, line_number, "Unable to set variable of type %s.\n", SwigType_str(t, 0)); +      } +      Printv(setf->code, "  return 0;\n", NULL); +      Append(setf->code, "fail:\n"); +      Printv(setf->code, "  return 1;\n", NULL); +    } else { +      /* Is a readonly variable.  Issue an error */ +      if (CPlusPlus) { +	Printf(setf->def, "SWIGINTERN int %s(PyObject *) {", varsetname); +      } else { +	Printf(setf->def, "SWIGINTERN int %s(PyObject *_val SWIGUNUSED) {", varsetname); +      } +      Printv(setf->code, "  SWIG_Error(SWIG_AttributeError,\"Variable ", iname, " is read-only.\");\n", "  return 1;\n", NIL); +    } + +    Append(setf->code, "}\n"); +    Wrapper_print(setf, f_wrappers); + +    /* Create a function for getting the value of a variable */ +    Setattr(n, "wrap:name", vargetname); +    if (builtin && in_class) { +      String *get_wrapper = Swig_name_wrapper(getname); +      Setattr(n, "pybuiltin:getter", get_wrapper); +      Delete(get_wrapper); +    } +    int addfail = 0; +    Printf(getf->def, "SWIGINTERN PyObject *%s(void) {", vargetname); +    Wrapper_add_local(getf, "pyobj", "PyObject *pyobj = 0"); +    if (builtin) { +      Wrapper_add_local(getf, "self", "PyObject *self = 0"); +      Append(getf->code, "  (void)self;\n"); +    } +    if ((tm = Swig_typemap_lookup("varout", n, name, 0))) { +      Replaceall(tm, "$result", "pyobj"); +      addfail = emit_action_code(n, getf->code, tm); +      Delete(tm); +    } else { +      Swig_warning(WARN_TYPEMAP_VAROUT_UNDEF, input_file, line_number, "Unable to read variable of type %s\n", SwigType_str(t, 0)); +    } +    Append(getf->code, "  return pyobj;\n"); +    if (addfail) { +      Append(getf->code, "fail:\n"); +      Append(getf->code, "  return NULL;\n"); +    } +    Append(getf->code, "}\n"); + +    Wrapper_print(getf, f_wrappers); + +    /* Now add this to the variable linking mechanism */ +    Printf(f_init, "\t SWIG_addvarlink(globals, \"%s\", %s, %s);\n", iname, vargetname, varsetname); +    if (builtin && shadow && !assignable && !in_class) { +      Printf(f_init, "\t PyDict_SetItemString(md, \"%s\", PyObject_GetAttrString(globals, \"%s\"));\n", iname, iname); +      Printf(f_init, "\t SwigPyBuiltin_AddPublicSymbol(public_interface, \"%s\");\n", iname); +    } +    Delete(vargetname); +    Delete(varsetname); +    Delete(getname); +    Delete(setname); +    DelWrapper(setf); +    DelWrapper(getf); +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * constantWrapper() +   * ------------------------------------------------------------ */ + +  /* Determine if the node requires the _swigconstant code to be generated */ +  bool needs_swigconstant(Node *n) { +    SwigType *type = Getattr(n, "type"); +    SwigType *qtype = SwigType_typedef_resolve_all(type); +    SwigType *uqtype = SwigType_strip_qualifiers(qtype); +    bool result = false; + +    /* Note, that we need special handling for function pointers, as +     * SwigType_base(fptr) does not return the underlying pointer-to-function +     * type but the return-type of function. */ +    if (!SwigType_isfunction(uqtype) && !SwigType_isfunctionpointer(uqtype)) { +      SwigType *basetype = SwigType_base(uqtype); +      result = SwigType_isclass(basetype) != 0; +      Delete(basetype); +    } + +    Delete(qtype); +    Delete(uqtype); + +    return result; +  } + +  virtual int constantWrapper(Node *n) { +    String *name = Getattr(n, "name"); +    String *iname = Getattr(n, "sym:name"); +    SwigType *type = Getattr(n, "type"); +    String *rawval = Getattr(n, "rawval"); +    String *value = rawval ? rawval : Getattr(n, "value"); +    String *tm; +    int have_tm = 0; +    int have_builtin_symname = 0; + +    if (!addSymbol(iname, n)) +      return SWIG_ERROR; + +    /* Special hook for member pointer */ +    if (SwigType_type(type) == T_MPOINTER) { +      String *wname = Swig_name_wrapper(iname); +      String *str = SwigType_str(type, wname); +      Printf(f_header, "static %s = %s;\n", str, value); +      Delete(str); +      value = wname; +    } + +    if ((tm = Swig_typemap_lookup("consttab", n, name, 0))) { +      Replaceall(tm, "$value", value); +      Printf(const_code, "%s,\n", tm); +      Delete(tm); +      have_tm = 1; +    } + + +    if (builtin && in_class && Getattr(n, "pybuiltin:symname")) { +      have_builtin_symname = 1; +      Swig_require("builtin_constantWrapper", n, "*sym:name", "pybuiltin:symname", NIL); +      Setattr(n, "sym:name", Getattr(n, "pybuiltin:symname")); +    } + +    if ((tm = Swig_typemap_lookup("constcode", n, name, 0))) { +      Replaceall(tm, "$value", value); +      if (needs_swigconstant(n) && !builtin && shadow && !(shadow & PYSHADOW_MEMBER) && (!in_class || !Getattr(n, "feature:python:callback"))) { +	// Generate `*_swigconstant()` method which registers the new constant. +	// +	// *_swigconstant methods are required for constants of class type. +	// Class types are registered in shadow file (see *_swigregister). The +	// instances of class must be created (registered) after the type is +	// registered, so we can't let SWIG_init() to register constants of +	// class type (the SWIG_init() is called before shadow classes are +	// defined and registered). +        Printf(f_wrappers, "SWIGINTERN PyObject *%s_swigconstant(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {\n", iname); +        Printf(f_wrappers, tab2 "PyObject *module;\n"); +        Printf(f_wrappers, tab2 "PyObject *d;\n"); +	Printf(f_wrappers, tab2 "if (!SWIG_Python_UnpackTuple(args, \"swigconstant\", 1, 1, &module)) return NULL;\n"); +        Printf(f_wrappers, tab2 "d = PyModule_GetDict(module);\n"); +        Printf(f_wrappers, tab2 "if (!d) return NULL;\n"); +        Printf(f_wrappers, tab2 "%s\n", tm); +        Printf(f_wrappers, tab2 "return SWIG_Py_Void();\n"); +        Printf(f_wrappers, "}\n\n\n"); + +        // Register the method in SwigMethods array +	String *cname = NewStringf("%s_swigconstant", iname); +	add_method(cname, cname, 0, 0, 1, 1, 1); +	Delete(cname); +      } else { +        Printf(f_init, "%s\n", tm); +      } +      Delete(tm); +      have_tm = 1; +    } + +    if (have_builtin_symname) +      Swig_restore(n); + +    if (!have_tm) { +      Swig_warning(WARN_TYPEMAP_CONST_UNDEF, input_file, line_number, "Unsupported constant value.\n"); +      return SWIG_NOWRAP; +    } + +    if (!builtin && shadow && !(shadow & PYSHADOW_MEMBER)) { +      String *f_s; +      if (!in_class) { +	f_s = f_shadow; +      } else { +	f_s = Getattr(n, "feature:python:callback") ? NIL : f_shadow_stubs; +      } + +      if (f_s) { +	if (needs_swigconstant(n)) { +	  Printv(f_s, "\n",NIL); +	  Printv(f_s, module, ".", iname, "_swigconstant(",module,")\n", NIL); +	} +	Printv(f_s, iname, " = ", module, ".", iname, "\n", NIL); +	if (have_docstring(n)) +	  Printv(f_s, docstring(n, AUTODOC_CONST, tab4), "\n", NIL); +      } +    } +    return SWIG_OK; +  } + + +  /* ------------------------------------------------------------ +   * nativeWrapper() +   * ------------------------------------------------------------ */ + +  virtual int nativeWrapper(Node *n) { +    String *name = Getattr(n, "sym:name"); +    String *wrapname = Getattr(n, "wrap:name"); + +    if (!addSymbol(wrapname, n)) +      return SWIG_ERROR; + +    add_method(name, wrapname, 0); +    if (!builtin && shadow) { +      Printv(f_shadow_stubs, name, " = ", module, ".", name, "\n", NIL); +    } +    return SWIG_OK; +  } + + + +  /* ---------------------------------------------------------------------------- +   * BEGIN C++ Director Class modifications +   * ------------------------------------------------------------------------- */ + +  /* C++/Python polymorphism demo code +   * +   * TODO +   * +   * Move some boilerplate code generation to Swig_...() functions. +   * +   */ + +  /* --------------------------------------------------------------- +   * classDirectorMethod() +   * +   * Emit a virtual director method to pass a method call on to the +   * underlying Python object. +   * ** Moved down due to gcc-2.96 internal error ** +   * --------------------------------------------------------------- */ + +  int classDirectorMethods(Node *n); + +  int classDirectorMethod(Node *n, Node *parent, String *super); + +  /* ------------------------------------------------------------ +   * classDirectorConstructor() +   * ------------------------------------------------------------ */ + +  int classDirectorConstructor(Node *n) { +    Node *parent = Getattr(n, "parentNode"); +    String *sub = NewString(""); +    String *decl = Getattr(n, "decl"); +    String *supername = Swig_class_name(parent); +    String *classname = NewString(""); +    Printf(classname, "SwigDirector_%s", supername); + +    /* insert self parameter */ +    Parm *p; +    ParmList *superparms = Getattr(n, "parms"); +    ParmList *parms = CopyParmList(superparms); +    String *type = NewString("PyObject"); +    SwigType_add_pointer(type); +    p = NewParm(type, NewString("self"), n); +    set_nextSibling(p, parms); +    parms = p; + +    if (!Getattr(n, "defaultargs")) { +      /* constructor */ +      { +	Wrapper *w = NewWrapper(); +	String *call; +	String *basetype = Getattr(parent, "classtype"); +	String *target = Swig_method_decl(0, decl, classname, parms, 0); +	call = Swig_csuperclass_call(0, basetype, superparms); +	Printf(w->def, "%s::%s: %s, Swig::Director(self) { \n", classname, target, call); +	Printf(w->def, "   SWIG_DIRECTOR_RGTR((%s *)this, this); \n", basetype); +	Append(w->def, "}\n"); +	Delete(target); +	Wrapper_print(w, f_directors); +	Delete(call); +	DelWrapper(w); +      } + +      /* constructor header */ +      { +	String *target = Swig_method_decl(0, decl, classname, parms, 1); +	Printf(f_directors_h, "    %s;\n", target); +	Delete(target); +      } +    } + +    Delete(sub); +    Delete(classname); +    Delete(supername); +    Delete(parms); +    return Language::classDirectorConstructor(n); +  } + +  /* ------------------------------------------------------------ +   * classDirectorDefaultConstructor() +   * ------------------------------------------------------------ */ + +  int classDirectorDefaultConstructor(Node *n) { +    String *classname = Swig_class_name(n); +    { +      Node *parent = Swig_methodclass(n); +      String *basetype = Getattr(parent, "classtype"); +      Wrapper *w = NewWrapper(); +      Printf(w->def, "SwigDirector_%s::SwigDirector_%s(PyObject *self) : Swig::Director(self) { \n", classname, classname); +      Printf(w->def, "   SWIG_DIRECTOR_RGTR((%s *)this, this); \n", basetype); +      Append(w->def, "}\n"); +      Wrapper_print(w, f_directors); +      DelWrapper(w); +    } +    Printf(f_directors_h, "    SwigDirector_%s(PyObject *self);\n", classname); +    Delete(classname); +    return Language::classDirectorDefaultConstructor(n); +  } + + +  /* ------------------------------------------------------------ +   * classDirectorInit() +   * ------------------------------------------------------------ */ + +  int classDirectorInit(Node *n) { +    String *declaration = Swig_director_declaration(n); +    Printf(f_directors_h, "\n"); +    Printf(f_directors_h, "%s\n", declaration); +    Printf(f_directors_h, "public:\n"); +    Delete(declaration); +    return Language::classDirectorInit(n); +  } + +  /* ------------------------------------------------------------ +   * classDirectorEnd() +   * ------------------------------------------------------------ */ + +  int classDirectorEnd(Node *n) { +    String *classname = Swig_class_name(n); + +    if (dirprot_mode()) { +      /* +         This implementation uses a std::map<std::string,int>. + +         It should be possible to rewrite it using a more elegant way, +         like copying the Java approach for the 'override' array. + +         But for now, this seems to be the least intrusive way. +       */ +      Printf(f_directors_h, "\n"); +      Printf(f_directors_h, "/* Internal director utilities */\n"); +      Printf(f_directors_h, "public:\n"); +      Printf(f_directors_h, "    bool swig_get_inner(const char *swig_protected_method_name) const {\n"); +      Printf(f_directors_h, "      std::map<std::string, bool>::const_iterator iv = swig_inner.find(swig_protected_method_name);\n"); +      Printf(f_directors_h, "      return (iv != swig_inner.end() ? iv->second : false);\n"); +      Printf(f_directors_h, "    }\n"); + +      Printf(f_directors_h, "    void swig_set_inner(const char *swig_protected_method_name, bool swig_val) const {\n"); +      Printf(f_directors_h, "      swig_inner[swig_protected_method_name] = swig_val;\n"); +      Printf(f_directors_h, "    }\n"); +      Printf(f_directors_h, "private:\n"); +      Printf(f_directors_h, "    mutable std::map<std::string, bool> swig_inner;\n"); + +    } +    if (director_method_index) { +      Printf(f_directors_h, "\n"); +      Printf(f_directors_h, "#if defined(SWIG_PYTHON_DIRECTOR_VTABLE)\n"); +      Printf(f_directors_h, "/* VTable implementation */\n"); +      Printf(f_directors_h, "    PyObject *swig_get_method(size_t method_index, const char *method_name) const {\n"); +      Printf(f_directors_h, "      PyObject *method = vtable[method_index];\n"); +      Printf(f_directors_h, "      if (!method) {\n"); +      Printf(f_directors_h, "        swig::SwigVar_PyObject name = SWIG_Python_str_FromChar(method_name);\n"); +      Printf(f_directors_h, "        method = PyObject_GetAttr(swig_get_self(), name);\n"); +      Printf(f_directors_h, "        if (!method) {\n"); +      Printf(f_directors_h, "          std::string msg = \"Method in class %s doesn't exist, undefined \";\n", classname); +      Printf(f_directors_h, "          msg += method_name;\n"); +      Printf(f_directors_h, "          Swig::DirectorMethodException::raise(msg.c_str());\n"); +      Printf(f_directors_h, "        }\n"); +      Printf(f_directors_h, "        vtable[method_index] = method;\n"); +      Printf(f_directors_h, "      }\n"); +      Printf(f_directors_h, "      return method;\n"); +      Printf(f_directors_h, "    }\n"); +      Printf(f_directors_h, "private:\n"); +      Printf(f_directors_h, "    mutable swig::SwigVar_PyObject vtable[%d];\n", director_method_index); +      Printf(f_directors_h, "#endif\n\n"); +    } + +    Printf(f_directors_h, "};\n\n"); +    return Language::classDirectorEnd(n); +  } + + +  /* ------------------------------------------------------------ +   * classDirectorDisown() +   * ------------------------------------------------------------ */ + +  int classDirectorDisown(Node *n) { +    int result; +    int oldshadow = shadow; +    /* disable shadowing */ +    if (shadow) +      shadow = shadow | PYSHADOW_MEMBER; +    result = Language::classDirectorDisown(n); +    shadow = oldshadow; +    if (shadow) { +      if (builtin) { +	String *rname = SwigType_namestr(real_classname); +	Printf(builtin_methods, "  { \"__disown__\", Swig::Director::swig_pyobj_disown< %s >, METH_NOARGS, \"\" },\n", rname); +	Delete(rname); +      } else { +	String *symname = Getattr(n, "sym:name"); +	String *mrename = Swig_name_disown(NSPACE_TODO, symname);	//Getattr(n, "name")); +	Printv(f_shadow, tab4, "def __disown__(self):\n", NIL); +	Printv(f_shadow, tab8, "self.this.disown()\n", NIL); +	Printv(f_shadow, tab8, module, ".", mrename, "(self)\n", NIL); +	Printv(f_shadow, tab8, "return weakref.proxy(self)\n", NIL); +	Delete(mrename); +      } +    } +    return result; +  } + +  /* ---------------------------------------------------------------------------- +   * END of C++ Director Class modifications +   * ------------------------------------------------------------------------- */ + + +  /* ------------------------------------------------------------ +   * classDeclaration() +   * ------------------------------------------------------------ */ + +  virtual int classDeclaration(Node *n) { +    if (shadow && !Getattr(n, "feature:onlychildren")) { +      Node *mod = Getattr(n, "module"); +      if (mod) { +	String *modname = Getattr(mod, "name"); +	Node *options = Getattr(mod, "options"); +	String *pkg = options ? Getattr(options, "package") : 0; +	String *sym = Getattr(n, "sym:name"); +	String *importname = import_name_string(package, mainmodule, pkg, modname, sym); +	Setattr(n, "python:proxy", importname); +	Delete(importname); +      } +    } +    int result = Language::classDeclaration(n); +    return result; +  } + +  /* ------------------------------------------------------------ +   * classHandler() +   * ------------------------------------------------------------ */ + +  String *add_explicit_scope(String *s) { +    if (!Strstr(s, "::")) { +      String *ss = NewStringf("::%s", s); +      Delete(s); +      s = ss; +    } +    return s; +  } + +  void builtin_pre_decl(Node *n) { +    String *name = Getattr(n, "name"); +    String *rname = add_explicit_scope(SwigType_namestr(name)); +    String *mname = SwigType_manglestr(rname); + +    Printf(f_init, "\n/* type '%s' */\n", rname); +    Printf(f_init, "    builtin_pytype = (PyTypeObject *)&SwigPyBuiltin_%s_type;\n", mname); +    Printf(f_init, "    builtin_pytype->tp_dict = d = PyDict_New();\n"); + +    Delete(rname); +    Delete(mname); +  } + +  void builtin_post_decl(File *f, Node *n) { +    String *name = Getattr(n, "name"); +    String *pname = Copy(name); +    SwigType_add_pointer(pname); +    String *symname = Getattr(n, "sym:name"); +    String *rname = add_explicit_scope(SwigType_namestr(name)); +    String *mname = SwigType_manglestr(rname); +    String *pmname = SwigType_manglestr(pname); +    String *templ = NewStringf("SwigPyBuiltin_%s", mname); +    int funpack = fastunpack; +    static String *tp_new = NewString("PyType_GenericNew"); + +    if (have_builtin_static_member_method_callback) { +      Printf(f_init, "  SWIG_Python_FixMethods(SwigPyBuiltin_%s_methods, swig_const_table, swig_types, swig_type_initial);\n", mname); +    } + +    Printv(f_init, "  SwigPyBuiltin_SetMetaType(builtin_pytype, metatype);\n", NIL); + +    // We can’t statically initialize a structure member with a function defined in another C module +    // So this is done in the initialization function instead, see https://docs.python.org/2/extending/newtypes.html +    Printf(f_init, "  builtin_pytype->tp_new = %s;\n", getSlot(n, "feature:python:tp_new", tp_new)); + +    Printv(f_init, "  builtin_base_count = 0;\n", NIL); +    List *baselist = Getattr(n, "bases"); +    if (baselist) { +      int base_count = 0; +      for (Iterator b = First(baselist); b.item; b = Next(b)) { +	String *bname = Getattr(b.item, "name"); +	if (!bname || GetFlag(b.item, "feature:ignore")) +	  continue; +	base_count++; +	String *base_name = Copy(bname); +	SwigType_add_pointer(base_name); +	String *base_mname = SwigType_manglestr(base_name); +	Printf(f_init, "  builtin_basetype = SWIG_MangledTypeQuery(\"%s\");\n", base_mname); +	Printv(f_init, "  if (builtin_basetype && builtin_basetype->clientdata && ((SwigPyClientData *) builtin_basetype->clientdata)->pytype) {\n", NIL); +	Printv(f_init, "    builtin_bases[builtin_base_count++] = ((SwigPyClientData *) builtin_basetype->clientdata)->pytype;\n", NIL); +	Printv(f_init, "  } else {\n", NIL); +	Printf(f_init, "    PyErr_SetString(PyExc_TypeError, \"Could not create type '%s' as base '%s' has not been initialized.\\n\");\n", symname, bname); +	Printv(f_init, "#if PY_VERSION_HEX >= 0x03000000\n", NIL); +	Printv(f_init, "      return NULL;\n", NIL); +	Printv(f_init, "#else\n", NIL); +	Printv(f_init, "      return;\n", NIL); +	Printv(f_init, "#endif\n", NIL); +	Printv(f_init, "  }\n", NIL); +	Delete(base_name); +	Delete(base_mname); +      } +      if (base_count > max_bases) +	max_bases = base_count; +    } +    Printv(f_init, "  builtin_bases[builtin_base_count] = NULL;\n", NIL); +    Printv(f_init, "  SwigPyBuiltin_InitBases(builtin_pytype, builtin_bases);\n", NIL); +    builtin_bases_needed = 1; + +    // Check for non-public destructor, in which case tp_dealloc will issue +    // a warning and allow the memory to leak.  Any class that doesn't explicitly +    // have a private/protected destructor has an implicit public destructor. +    static String *tp_dealloc_bad = NewString("SwigPyBuiltin_BadDealloc"); + +    String *getset_name = NewStringf("%s_getset", templ); +    String *methods_name = NewStringf("%s_methods", templ); +    String *getset_def = NewString(""); +    Printf(getset_def, "SWIGINTERN PyGetSetDef %s[] = {\n", getset_name); + +    // All objects have 'this' and 'thisown' attributes +    Printv(f_init, "PyDict_SetItemString(d, \"this\", this_descr);\n", NIL); +    Printv(f_init, "PyDict_SetItemString(d, \"thisown\", thisown_descr);\n", NIL); + +    // Now, the rest of the attributes +    for (Iterator member_iter = First(builtin_getset); member_iter.item; member_iter = Next(member_iter)) { +      String *memname = member_iter.key; +      Hash *mgetset = member_iter.item; +      String *getter = Getattr(mgetset, "getter"); +      String *setter = Getattr(mgetset, "setter"); +      const char *getter_closure = getter ? funpack ? "SwigPyBuiltin_FunpackGetterClosure" : "SwigPyBuiltin_GetterClosure" : "0"; +      const char *setter_closure = setter ? funpack ? "SwigPyBuiltin_FunpackSetterClosure" : "SwigPyBuiltin_SetterClosure" : "0"; +      String *gspair = NewStringf("%s_%s_getset", symname, memname); +      Printf(f, "static SwigPyGetSet %s = { %s, %s };\n", gspair, getter ? getter : "0", setter ? setter : "0"); +      String *doc = Getattr(mgetset, "doc"); +      if (!doc) +	doc = NewStringf("%s.%s", name, memname); +      String *entry = NewStringf("{ (char *)\"%s\", %s, %s, (char *)\"%s\", &%s }", memname, getter_closure, setter_closure, doc, gspair); +      if (GetFlag(mgetset, "static")) { +	Printf(f, "static PyGetSetDef %s_def = %s;\n", gspair, entry); +	Printf(f_init, "static_getset = SwigPyStaticVar_new_getset(metatype, &%s_def);\n", gspair); +	Printf(f_init, "PyDict_SetItemString(d, static_getset->d_getset->name, (PyObject *) static_getset);\n"); +	Printf(f_init, "Py_DECREF(static_getset);\n"); +      } else { +	Printf(getset_def, "    %s,\n", entry); +      } +      Delete(gspair); +      Delete(entry); +    } +    Printv(f, getset_def, "    { NULL, NULL, NULL, NULL, NULL } /* Sentinel */\n", "};\n\n", NIL); + +    // Rich compare function +    Hash *richcompare = Getattr(n, "python:richcompare"); +    String *richcompare_func = NewStringf("%s_richcompare", templ); +    assert(richcompare); +    Printf(f, "SWIGINTERN PyObject *\n"); +    Printf(f, "%s(PyObject *self, PyObject *other, int op) {\n", richcompare_func); +    Printf(f, "  PyObject *result = NULL;\n"); +    if (!funpack) { +      Printf(f, "  PyObject *tuple = PyTuple_New(1);\n"); +      Printf(f, "  assert(tuple);\n"); +      Printf(f, "  PyTuple_SET_ITEM(tuple, 0, other);\n"); +      Printf(f, "  Py_XINCREF(other);\n"); +    } +    List *richcompare_list = SortedKeys(richcompare, 0); +    Iterator rich_iter = First(richcompare_list); +    if (rich_iter.item) { +      Printf(f, "  switch (op) {\n"); +      for (; rich_iter.item; rich_iter = Next(rich_iter)) +	Printf(f, "    case %s : result = %s(self, %s); break;\n", rich_iter.item, Getattr(richcompare, rich_iter.item), funpack ? "other" : "tuple"); +      Printv(f, "    default : break;\n", NIL); +      Printf(f, "  }\n"); +    } +    Delete(richcompare_list); +    Printv(f, "  if (!result) {\n", NIL); +    Printv(f, "    if (SwigPyObject_Check(self) && SwigPyObject_Check(other)) {\n", NIL); +    Printv(f, "      result = SwigPyObject_richcompare((SwigPyObject *)self, (SwigPyObject *)other, op);\n", NIL); +    Printv(f, "    } else {\n", NIL); +    Printv(f, "      result = Py_NotImplemented;\n", NIL); +    Printv(f, "      Py_INCREF(result);\n", NIL); +    Printv(f, "    }\n", NIL); +    Printv(f, "  }\n", NIL); +    if (!funpack) +      Printf(f, "  Py_DECREF(tuple);\n"); +    Printf(f, "  return result;\n"); +    Printf(f, "}\n\n"); + +    // Methods +    Printf(f, "SWIGINTERN PyMethodDef %s_methods[] = {\n", templ); +    Dump(builtin_methods, f); +    Printf(f, "  { NULL, NULL, 0, NULL } /* Sentinel */\n};\n\n"); + +    // No instance dict for nondynamic objects +    if (GetFlag(n, "feature:python:nondynamic")) +      Setattr(n, "feature:python:tp_setattro", "SWIG_Python_NonDynamicSetAttr"); + +    Node *mod = Getattr(n, "module"); +    String *modname = mod ? Getattr(mod, "name") : 0; +    String *quoted_symname; +    if (package) { +      if (modname) +	quoted_symname = NewStringf("\"%s.%s.%s\"", package, modname, symname); +      else +	quoted_symname = NewStringf("\"%s.%s\"", package, symname); +    } else { +      if (modname) +	quoted_symname = NewStringf("\"%s.%s\"", modname, symname); +      else +	quoted_symname = NewStringf("\"%s\"", symname); +    } +    String *quoted_tp_doc_str = NewStringf("\"%s\"", getSlot(n, "feature:python:tp_doc")); +    String *tp_init = NewString(builtin_tp_init ? Char(builtin_tp_init) : Swig_directorclass(n) ? "0" : "SwigPyBuiltin_BadInit"); +    String *tp_flags = NewString("Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_CHECKTYPES"); +    String *tp_flags_py3 = NewString("Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE"); + +    static String *tp_basicsize = NewStringf("sizeof(SwigPyObject)"); +    static String *tp_dictoffset_default = NewString("offsetof(SwigPyObject, dict)"); +    static String *tp_hash = NewString("SwigPyObject_hash"); +    String *tp_as_number = NewStringf("&%s_type.as_number", templ); +    String *tp_as_sequence = NewStringf("&%s_type.as_sequence", templ); +    String *tp_as_mapping = NewStringf("&%s_type.as_mapping", templ); +    String *tp_as_buffer = NewStringf("&%s_type.as_buffer", templ); + +    Printf(f, "static PyHeapTypeObject %s_type = {\n", templ); + +    // PyTypeObject ht_type +    Printf(f, "  {\n"); +    Printv(f, "#if PY_VERSION_HEX >= 0x03000000\n", NIL); +    Printv(f, "    PyVarObject_HEAD_INIT(NULL, 0)\n", NIL); +    Printv(f, "#else\n", NIL); +    Printf(f, "    PyObject_HEAD_INIT(NULL)\n"); +    printSlot(f, getSlot(), "ob_size"); +    Printv(f, "#endif\n", NIL); +    printSlot(f, quoted_symname, "tp_name"); +    printSlot(f, getSlot(n, "feature:python:tp_basicsize", tp_basicsize), "tp_basicsize"); +    printSlot(f, getSlot(n, "feature:python:tp_itemsize"), "tp_itemsize"); +    printSlot(f, getSlot(n, "feature:python:tp_dealloc", tp_dealloc_bad), "tp_dealloc", "destructor"); +    Printv(f, "#if PY_VERSION_HEX < 0x030800b4\n", NIL); +    printSlot(f, getSlot(n, "feature:python:tp_print"), "tp_print", "printfunc"); +    Printv(f, "#else\n", NIL); +    printSlot(f, getSlot(n, "feature:python:tp_vectorcall_offset"), "tp_vectorcall_offset", "Py_ssize_t"); +    Printv(f, "#endif\n", NIL); +    printSlot(f, getSlot(n, "feature:python:tp_getattr"), "tp_getattr", "getattrfunc"); +    printSlot(f, getSlot(n, "feature:python:tp_setattr"), "tp_setattr", "setattrfunc"); +    Printv(f, "#if PY_VERSION_HEX >= 0x03000000\n", NIL); +    printSlot(f, getSlot(n, "feature:python:tp_compare"), "tp_compare"); +    Printv(f, "#else\n", NIL); +    printSlot(f, getSlot(n, "feature:python:tp_compare"), "tp_compare", "cmpfunc"); +    Printv(f, "#endif\n", NIL); +    printSlot(f, getSlot(n, "feature:python:tp_repr"), "tp_repr", "reprfunc"); +    printSlot(f, getSlot(n, "feature:python:tp_as_number", tp_as_number), "tp_as_number"); +    printSlot(f, getSlot(n, "feature:python:tp_as_sequence", tp_as_sequence), "tp_as_sequence"); +    printSlot(f, getSlot(n, "feature:python:tp_as_mapping", tp_as_mapping), "tp_as_mapping"); +    printSlot(f, getSlot(n, "feature:python:tp_hash", tp_hash), "tp_hash", "hashfunc"); +    printSlot(f, getSlot(n, "feature:python:tp_call"), "tp_call", "ternaryfunc"); +    printSlot(f, getSlot(n, "feature:python:tp_str"), "tp_str", "reprfunc"); +    printSlot(f, getSlot(n, "feature:python:tp_getattro"), "tp_getattro", "getattrofunc"); +    printSlot(f, getSlot(n, "feature:python:tp_setattro"), "tp_setattro", "setattrofunc"); +    printSlot(f, getSlot(n, "feature:python:tp_as_buffer", tp_as_buffer), "tp_as_buffer"); +    Printv(f, "#if PY_VERSION_HEX >= 0x03000000\n", NIL); +    printSlot(f, getSlot(n, "feature:python:tp_flags", tp_flags_py3), "tp_flags"); +    Printv(f, "#else\n", NIL); +    printSlot(f, getSlot(n, "feature:python:tp_flags", tp_flags), "tp_flags"); +    Printv(f, "#endif\n", NIL); +    if (have_docstring(n)) { +      String *ds = cdocstring(n, AUTODOC_CLASS); +      String *tp_doc = NewString(""); +      Printf(tp_doc, "\"%s\"", ds); +      Delete(ds); +      printSlot(f, tp_doc, "tp_doc"); +      Delete(tp_doc); +    } else { +      printSlot(f, quoted_tp_doc_str, "tp_doc"); +    } +    printSlot(f, getSlot(n, "feature:python:tp_traverse"), "tp_traverse", "traverseproc"); +    printSlot(f, getSlot(n, "feature:python:tp_clear"), "tp_clear", "inquiry"); +    printSlot(f, getSlot(n, "feature:python:tp_richcompare", richcompare_func), "tp_richcompare", "richcmpfunc"); +    printSlot(f, getSlot(n, "feature:python:tp_weaklistoffset"), "tp_weaklistoffset"); +    printSlot(f, getSlot(n, "feature:python:tp_iter"), "tp_iter", "getiterfunc"); +    printSlot(f, getSlot(n, "feature:python:tp_iternext"), "tp_iternext", "iternextfunc"); +    printSlot(f, getSlot(n, "feature:python:tp_methods", methods_name), "tp_methods"); +    printSlot(f, getSlot(n, "feature:python:tp_members"), "tp_members"); +    printSlot(f, getSlot(n, "feature:python:tp_getset", getset_name), "tp_getset"); +    printSlot(f, getSlot(n, "feature:python:tp_base"), "tp_base"); +    printSlot(f, getSlot(n, "feature:python:tp_dict"), "tp_dict"); +    printSlot(f, getSlot(n, "feature:python:tp_descr_get"), "tp_descr_get", "descrgetfunc"); +    printSlot(f, getSlot(n, "feature:python:tp_descr_set"), "tp_descr_set", "descrsetfunc"); +    printSlot(f, getSlot(n, "feature:python:tp_dictoffset", tp_dictoffset_default), "tp_dictoffset", "Py_ssize_t"); +    printSlot(f, getSlot(n, "feature:python:tp_init", tp_init), "tp_init", "initproc"); +    printSlot(f, getSlot(n, "feature:python:tp_alloc"), "tp_alloc", "allocfunc"); +    printSlot(f, getSlot(), "tp_new", "newfunc"); +    printSlot(f, getSlot(n, "feature:python:tp_free"), "tp_free", "freefunc"); +    printSlot(f, getSlot(n, "feature:python:tp_is_gc"), "tp_is_gc", "inquiry"); +    printSlot(f, getSlot(n, "feature:python:tp_bases"), "tp_bases", "PyObject *"); +    printSlot(f, getSlot(n, "feature:python:tp_mro"), "tp_mro", "PyObject *"); +    printSlot(f, getSlot(n, "feature:python:tp_cache"), "tp_cache", "PyObject *"); +    printSlot(f, getSlot(n, "feature:python:tp_subclasses"), "tp_subclasses", "PyObject *"); +    printSlot(f, getSlot(n, "feature:python:tp_weaklist"), "tp_weaklist", "PyObject *"); +    printSlot(f, getSlot(n, "feature:python:tp_del"), "tp_del", "destructor"); +    printSlot(f, getSlot(n, "feature:python:tp_version_tag"), "tp_version_tag", "int"); +    Printv(f, "#if PY_VERSION_HEX >= 0x03040000\n", NIL); +    printSlot(f, getSlot(n, "feature:python:tp_finalize"), "tp_finalize", "destructor"); +    Printv(f, "#endif\n", NIL); +    Printv(f, "#if PY_VERSION_HEX >= 0x03080000\n", NIL); +    printSlot(f, getSlot(n, "feature:python:tp_vectorcall"), "tp_vectorcall", "vectorcallfunc"); +    Printv(f, "#endif\n", NIL); +    Printv(f, "#if (PY_VERSION_HEX >= 0x03080000) && (PY_VERSION_HEX < 0x03090000)\n", NIL); +    printSlot(f, getSlot(), "tp_print"); +    Printv(f, "#endif\n", NIL); + +    Printv(f, "#ifdef COUNT_ALLOCS\n", NIL); +    printSlot(f, getSlot(n, "feature:python:tp_allocs"), "tp_allocs", "Py_ssize_t"); +    printSlot(f, getSlot(n, "feature:python:tp_frees"), "tp_frees", "Py_ssize_t"); +    printSlot(f, getSlot(n, "feature:python:tp_maxalloc"), "tp_maxalloc", "Py_ssize_t"); +    printSlot(f, getSlot(n, "feature:python:tp_prev"), "tp_prev"); +    printSlot(f, getSlot(n, "feature:python:tp_next"), "tp_next"); +    Printv(f, "#endif\n", NIL); +    Printf(f, "  },\n"); + +    // PyAsyncMethods as_async +    Printv(f, "#if PY_VERSION_HEX >= 0x03050000\n", NIL); +    Printf(f, "  {\n"); +    printSlot(f, getSlot(n, "feature:python:am_await"), "am_await", "unaryfunc"); +    printSlot(f, getSlot(n, "feature:python:am_aiter"), "am_aiter", "unaryfunc"); +    printSlot(f, getSlot(n, "feature:python:am_anext"), "am_anext", "unaryfunc"); +    Printv(f, "# if PY_VERSION_HEX >= 0x030a0000\n", NIL); +    printSlot(f, getSlot(n, "feature:python:am_send"), "am_send", "sendfunc"); +    Printv(f, "# endif\n", NIL); +    Printf(f, "  },\n"); +    Printv(f, "#endif\n", NIL); + +    // PyNumberMethods as_number +    Printf(f, "  {\n"); +    printSlot(f, getSlot(n, "feature:python:nb_add"), "nb_add", "binaryfunc"); +    printSlot(f, getSlot(n, "feature:python:nb_subtract"), "nb_subtract", "binaryfunc"); +    printSlot(f, getSlot(n, "feature:python:nb_multiply"), "nb_multiply", "binaryfunc"); +    Printv(f, "#if PY_VERSION_HEX < 0x03000000\n", NIL); +    printSlot(f, getSlot(n, "feature:python:nb_divide"), "nb_divide", "binaryfunc"); +    Printv(f, "#endif\n", NIL); +    printSlot(f, getSlot(n, "feature:python:nb_remainder"), "nb_remainder", "binaryfunc"); +    printSlot(f, getSlot(n, "feature:python:nb_divmod"), "nb_divmod", "binaryfunc"); +    printSlot(f, getSlot(n, "feature:python:nb_power"), "nb_power", "ternaryfunc"); +    printSlot(f, getSlot(n, "feature:python:nb_negative"), "nb_negative", "unaryfunc"); +    printSlot(f, getSlot(n, "feature:python:nb_positive"), "nb_positive", "unaryfunc"); +    printSlot(f, getSlot(n, "feature:python:nb_absolute"), "nb_absolute", "unaryfunc"); +    printSlot(f, getSlot(n, "feature:python:nb_nonzero"), "nb_nonzero", "inquiry"); +    printSlot(f, getSlot(n, "feature:python:nb_invert"), "nb_invert", "unaryfunc"); +    printSlot(f, getSlot(n, "feature:python:nb_lshift"), "nb_lshift", "binaryfunc"); +    printSlot(f, getSlot(n, "feature:python:nb_rshift"), "nb_rshift", "binaryfunc"); +    printSlot(f, getSlot(n, "feature:python:nb_and"), "nb_and", "binaryfunc"); +    printSlot(f, getSlot(n, "feature:python:nb_xor"), "nb_xor", "binaryfunc"); +    printSlot(f, getSlot(n, "feature:python:nb_or"), "nb_or", "binaryfunc"); +    Printv(f, "#if PY_VERSION_HEX < 0x03000000\n", NIL); +    printSlot(f, getSlot(n, "feature:python:nb_coerce"), "nb_coerce", "coercion"); +    Printv(f, "#endif\n", NIL); +    printSlot(f, getSlot(n, "feature:python:nb_int"), "nb_int", "unaryfunc"); +    Printv(f, "#if PY_VERSION_HEX >= 0x03000000\n", NIL); +    printSlot(f, getSlot(n, "feature:python:nb_reserved"), "nb_reserved", "void *"); +    Printv(f, "#else\n", NIL); +    printSlot(f, getSlot(n, "feature:python:nb_long"), "nb_long", "unaryfunc"); +    Printv(f, "#endif\n", NIL); +    printSlot(f, getSlot(n, "feature:python:nb_float"), "nb_float", "unaryfunc"); +    Printv(f, "#if PY_VERSION_HEX < 0x03000000\n", NIL); +    printSlot(f, getSlot(n, "feature:python:nb_oct"), "nb_oct", "unaryfunc"); +    printSlot(f, getSlot(n, "feature:python:nb_hex"), "nb_hex", "unaryfunc"); +    Printv(f, "#endif\n", NIL); +    printSlot(f, getSlot(n, "feature:python:nb_inplace_add"), "nb_inplace_add", "binaryfunc"); +    printSlot(f, getSlot(n, "feature:python:nb_inplace_subtract"), "nb_inplace_subtract", "binaryfunc"); +    printSlot(f, getSlot(n, "feature:python:nb_inplace_multiply"), "nb_inplace_multiply", "binaryfunc"); +    Printv(f, "#if PY_VERSION_HEX < 0x03000000\n", NIL); +    printSlot(f, getSlot(n, "feature:python:nb_inplace_divide"), "nb_inplace_divide", "binaryfunc"); +    Printv(f, "#endif\n", NIL); +    printSlot(f, getSlot(n, "feature:python:nb_inplace_remainder"), "nb_inplace_remainder", "binaryfunc"); +    printSlot(f, getSlot(n, "feature:python:nb_inplace_power"), "nb_inplace_power", "ternaryfunc"); +    printSlot(f, getSlot(n, "feature:python:nb_inplace_lshift"), "nb_inplace_lshift", "binaryfunc"); +    printSlot(f, getSlot(n, "feature:python:nb_inplace_rshift"), "nb_inplace_rshift", "binaryfunc"); +    printSlot(f, getSlot(n, "feature:python:nb_inplace_and"), "nb_inplace_and", "binaryfunc"); +    printSlot(f, getSlot(n, "feature:python:nb_inplace_xor"), "nb_inplace_xor", "binaryfunc"); +    printSlot(f, getSlot(n, "feature:python:nb_inplace_or"), "nb_inplace_or", "binaryfunc"); +    printSlot(f, getSlot(n, "feature:python:nb_floor_divide"), "nb_floor_divide", "binaryfunc"); +    printSlot(f, getSlot(n, "feature:python:nb_divide"), "nb_true_divide", "binaryfunc"); +    printSlot(f, getSlot(n, "feature:python:nb_inplace_floor_divide"), "nb_inplace_floor_divide", "binaryfunc"); +    printSlot(f, getSlot(n, "feature:python:nb_inplace_divide"), "nb_inplace_true_divide", "binaryfunc"); +    printSlot(f, getSlot(n, "feature:python:nb_index"), "nb_index", "unaryfunc"); +    Printv(f, "#if PY_VERSION_HEX >= 0x03050000\n", NIL); +    printSlot(f, getSlot(n, "feature:python:nb_matrix_multiply"), "nb_matrix_multiply", "binaryfunc"); +    printSlot(f, getSlot(n, "feature:python:nb_inplace_matrix_multiply"), "nb_inplace_matrix_multiply", "binaryfunc"); +    Printv(f, "#endif\n", NIL); +    Printf(f, "  },\n"); + +    // PyMappingMethods as_mapping; +    Printf(f, "  {\n"); +    printSlot(f, getSlot(n, "feature:python:mp_length"), "mp_length", "lenfunc"); +    printSlot(f, getSlot(n, "feature:python:mp_subscript"), "mp_subscript", "binaryfunc"); +    printSlot(f, getSlot(n, "feature:python:mp_ass_subscript"), "mp_ass_subscript", "objobjargproc"); +    Printf(f, "  },\n"); + +    // PySequenceMethods as_sequence; +    Printf(f, "  {\n"); +    printSlot(f, getSlot(n, "feature:python:sq_length"), "sq_length", "lenfunc"); +    printSlot(f, getSlot(n, "feature:python:sq_concat"), "sq_concat", "binaryfunc"); +    printSlot(f, getSlot(n, "feature:python:sq_repeat"), "sq_repeat", "ssizeargfunc"); +    printSlot(f, getSlot(n, "feature:python:sq_item"), "sq_item", "ssizeargfunc"); +    Printv(f, "#if PY_VERSION_HEX >= 0x03000000\n", NIL); +    printSlot(f, getSlot(n, "feature:python:was_sq_slice"), "was_sq_slice", "void *"); +    Printv(f, "#else\n", NIL); +    printSlot(f, getSlot(n, "feature:python:sq_slice"), "sq_slice", "ssizessizeargfunc"); +    Printv(f, "#endif\n", NIL); +    printSlot(f, getSlot(n, "feature:python:sq_ass_item"), "sq_ass_item", "ssizeobjargproc"); +    Printv(f, "#if PY_VERSION_HEX >= 0x03000000\n", NIL); +    printSlot(f, getSlot(n, "feature:python:was_sq_ass_slice"), "was_sq_ass_slice", "void *"); +    Printv(f, "#else\n", NIL); +    printSlot(f, getSlot(n, "feature:python:sq_ass_slice"), "sq_ass_slice", "ssizessizeobjargproc"); +    Printv(f, "#endif\n", NIL); +    printSlot(f, getSlot(n, "feature:python:sq_contains"), "sq_contains", "objobjproc"); +    printSlot(f, getSlot(n, "feature:python:sq_inplace_concat"), "sq_inplace_concat", "binaryfunc"); +    printSlot(f, getSlot(n, "feature:python:sq_inplace_repeat"), "sq_inplace_repeat", "ssizeargfunc"); +    Printf(f, "  },\n"); + +    // PyBufferProcs as_buffer; +    Printf(f, "  {\n"); +    Printv(f, "#if PY_VERSION_HEX < 0x03000000\n", NIL); +    printSlot(f, getSlot(n, "feature:python:bf_getreadbuffer"), "bf_getreadbuffer", "readbufferproc"); +    printSlot(f, getSlot(n, "feature:python:bf_getwritebuffer"), "bf_getwritebuffer", "writebufferproc"); +    printSlot(f, getSlot(n, "feature:python:bf_getsegcount"), "bf_getsegcount", "segcountproc"); +    printSlot(f, getSlot(n, "feature:python:bf_getcharbuffer"), "bf_getcharbuffer", "charbufferproc"); +    Printv(f, "#endif\n", NIL); +    printSlot(f, getSlot(n, "feature:python:bf_getbuffer"), "bf_getbuffer", "getbufferproc"); +    printSlot(f, getSlot(n, "feature:python:bf_releasebuffer"), "bf_releasebuffer", "releasebufferproc"); +    Printf(f, "  },\n"); + +    // PyObject *ht_name, *ht_slots, *ht_qualname; +    printSlot(f, getSlot(n, "feature:python:ht_name"), "ht_name", "PyObject *"); +    printSlot(f, getSlot(n, "feature:python:ht_slots"), "ht_slots", "PyObject *"); +    Printv(f, "#if PY_VERSION_HEX >= 0x03030000\n", NIL); +    printSlot(f, getSlot(n, "feature:python:ht_qualname"), "ht_qualname", "PyObject *"); + +    // struct _dictkeysobject *ht_cached_keys; +    printSlot(f, getSlot(n, "feature:python:ht_cached_keys"), "ht_cached_keys"); +    Printv(f, "#endif\n", NIL); + +    // PyObject *ht_module; +    Printv(f, "#if PY_VERSION_HEX >= 0x03090000\n", NIL); +    printSlot(f, getSlot(n, "feature:python:ht_module"), "ht_module", "PyObject *"); +    Printv(f, "#endif\n", NIL); + +    // char *_ht_tpname; +    Printv(f, "#if PY_VERSION_HEX >= 0x030b0000\n", NIL); +    printSlot(f, getSlot(n, "feature:python:_ht_tpname"), "_ht_tpname", "char *"); + +    // struct _specialization_cache _spec_cache; +    Printf(f, "  {\n"); +    printSlot(f, getSlot(n, "feature:python:getitem"), "getitem", "PyObject *"); +    Printf(f, "  }\n"); +    Printv(f, "#endif\n", NIL); +    Printf(f, "};\n\n"); + +    String *clientdata = NewString(""); +    Printf(clientdata, "&%s_clientdata", templ); +    SwigType_remember_mangleddata(pmname, clientdata); + +    SwigType *smart = Swig_cparse_smartptr(n); +    if (smart) { +      SwigType_add_pointer(smart); +      String *smart_pmname = SwigType_manglestr(smart); +      SwigType_remember_mangleddata(smart_pmname, clientdata); +      Delete(smart_pmname); +    } + +    String *clientdata_klass = NewString("0"); +    if (GetFlag(n, "feature:implicitconv")) { +      Clear(clientdata_klass); +      Printf(clientdata_klass, "(PyObject *) &%s_type", templ); +    } + +    Printf(f, "SWIGINTERN SwigPyClientData %s_clientdata = {%s, 0, 0, 0, 0, 0, (PyTypeObject *)&%s_type};\n\n", templ, clientdata_klass, templ); + +    Printv(f_init, "    if (PyType_Ready(builtin_pytype) < 0) {\n", NIL); +    Printf(f_init, "      PyErr_SetString(PyExc_TypeError, \"Could not create type '%s'.\");\n", symname); +    Printv(f_init, "#if PY_VERSION_HEX >= 0x03000000\n", NIL); +    Printv(f_init, "      return NULL;\n", NIL); +    Printv(f_init, "#else\n", NIL); +    Printv(f_init, "      return;\n", NIL); +    Printv(f_init, "#endif\n", NIL); +    Printv(f_init, "    }\n", NIL); +    Printv(f_init, "    Py_INCREF(builtin_pytype);\n", NIL); +    Printf(f_init, "    PyModule_AddObject(m, \"%s\", (PyObject *)builtin_pytype);\n", symname); +    Printf(f_init, "    SwigPyBuiltin_AddPublicSymbol(public_interface, \"%s\");\n", symname); +    Printv(f_init, "    d = md;\n", NIL); + +    Delete(clientdata); +    Delete(smart); +    Delete(rname); +    Delete(pname); +    Delete(mname); +    Delete(pmname); +    Delete(templ); +    Delete(tp_flags); +    Delete(tp_flags_py3); +    Delete(tp_as_buffer); +    Delete(tp_as_mapping); +    Delete(tp_as_sequence); +    Delete(tp_as_number); +    Delete(quoted_symname); +    Delete(quoted_tp_doc_str); +    Delete(tp_init); +    Delete(clientdata_klass); +    Delete(richcompare_func); +    Delete(getset_name); +    Delete(methods_name); +  } + +  virtual int classHandler(Node *n) { +    File *f_shadow_file = f_shadow; +    Node *base_node = NULL; + +    if (shadow) { + +      /* Create new strings for building up a wrapper function */ +      have_constructor = 0; +      have_repr = 0; +      have_builtin_static_member_method_callback = false; + +      class_name = Getattr(n, "sym:name"); +      real_classname = Getattr(n, "name"); + +      if (!addSymbol(class_name, n)) +	return SWIG_ERROR; + +      if (builtin) { +	List *baselist = Getattr(n, "bases"); +	if (baselist && Len(baselist) > 0) { +	  Iterator b = First(baselist); +	  base_node = b.item; +	} +      } + +      shadow_indent = (String *) tab4; + +      /* Handle inheritance */ +      String *base_class = NewString(""); +      List *baselist = Getattr(n, "bases"); +      if (baselist && Len(baselist)) { +	Iterator b; +	b = First(baselist); +	while (b.item) { +	  String *bname = Getattr(b.item, "python:proxy"); +	  bool ignore = GetFlag(b.item, "feature:ignore") ? true : false; +	  if (!bname || ignore) { +	    if (!bname && !ignore) { +	      Swig_warning(WARN_TYPE_UNDEFINED_CLASS, Getfile(n), Getline(n), +			   "Base class '%s' ignored - unknown module name for base. Either import the appropriate module interface file or specify the name of the module in the %%import directive.\n", +			   SwigType_namestr(Getattr(b.item, "name"))); +	    } +	    b = Next(b); +	    continue; +	  } +	  Printv(base_class, bname, NIL); +	  b = Next(b); +	  if (b.item) { +            Printv(base_class, ", ", NIL); +	  } +	} +      } + +      if (builtin) { +	Hash *base_richcompare = NULL; +	Hash *richcompare = NULL; +	if (base_node) +	  base_richcompare = Getattr(base_node, "python:richcompare"); +	if (base_richcompare) +	  richcompare = Copy(base_richcompare); +	else +	  richcompare = NewHash(); +	Setattr(n, "python:richcompare", richcompare); +      } + +      /* dealing with abstract base class */ +      String *abcs = Getattr(n, "feature:python:abc"); +      if (abcs) { +	if (Len(base_class) > 0) +	  Printv(base_class, ", ", NIL); +	Printv(base_class, abcs, NIL); +      } + +      if (builtin) { +	if (have_docstring(n)) { +	  String *ds = cdocstring(n, AUTODOC_CLASS); +	  Setattr(n, "feature:python:tp_doc", ds); +	  Delete(ds); +	} else { +	  String *name = Getattr(n, "name"); +	  String *rname = add_explicit_scope(SwigType_namestr(name)); +	  Setattr(n, "feature:python:tp_doc", rname); +	  Delete(rname); +	} +      } else { +	if (GetFlag(n, "feature:python:nondynamic")) +	  Printv(f_shadow, "@_swig_add_metaclass(_SwigNonDynamicMeta)\n", NIL); +	Printv(f_shadow, "class ", class_name, NIL); + +	if (Len(base_class)) { +	  Printf(f_shadow, "(%s)", base_class); +	} else { +	  if (GetFlag(n, "feature:exceptionclass")) { +	    Printf(f_shadow, "(Exception)"); +	  } else { +	    Printf(f_shadow, "(object"); +	    /* Replace @_swig_add_metaclass above with below when support for python 2.7 is dropped +	    if (GetFlag(n, "feature:python:nondynamic")) { +	      Printf(f_shadow, ", metaclass=_SwigNonDynamicMeta"); +	    } +	    */ +	    Printf(f_shadow, ")"); +	  } +	} + +	Printf(f_shadow, ":\n"); + +	// write docstrings if requested +	if (have_docstring(n)) { +	  String *str = docstring(n, AUTODOC_CLASS, tab4); +	  if (str && Len(str)) +	    Printv(f_shadow, tab4, str, "\n\n", NIL); +	} + +	Printv(f_shadow, tab4, "thisown = property(lambda x: x.this.own(), ", "lambda x, v: x.this.own(v), doc=\"The membership flag\")\n", NIL); +	/* Add static attribute */ +	if (GetFlag(n, "feature:python:nondynamic")) { +	  Printv(f_shadow_file, tab4, "__setattr__ = _swig_setattr_nondynamic_instance_variable(object.__setattr__)\n", NIL); +	} +      } +    } + +    /* Emit all of the members */ + +    in_class = 1; +    if (builtin) +      builtin_pre_decl(n); + +    /* Override the shadow file so we can capture its methods */ +    f_shadow = NewString(""); + +    // Set up type check for director class constructor +    Clear(none_comparison); +    if (builtin && Swig_directorclass(n)) { +      String *p_real_classname = Copy(real_classname); +      SwigType_add_pointer(p_real_classname); +      String *mangle = SwigType_manglestr(p_real_classname); +      String *descriptor = NewStringf("SWIGTYPE%s", mangle); +      Printv(none_comparison, "self->ob_type != ((SwigPyClientData *)(", descriptor, ")->clientdata)->pytype", NIL); +      Delete(descriptor); +      Delete(mangle); +      Delete(p_real_classname); +    } else { +      Printv(none_comparison, "$arg != Py_None", NIL); +    } + +    Language::classHandler(n); + +    in_class = 0; + +    /* Complete the class */ +    if (shadow) { +      /* Generate a class registration function */ +      // Replace storing a pointer to underlying class with a smart pointer (intended for use with non-intrusive smart pointers) +      SwigType *smart = Swig_cparse_smartptr(n); +      SwigType *ct = Copy(smart ? smart : real_classname); +      SwigType_add_pointer(ct); +      SwigType *realct = Copy(real_classname); +      SwigType_add_pointer(realct); +      SwigType_remember(realct); +      if (builtin) { +	Printv(f_wrappers, builtin_closures_code, NIL); +	Delete(builtin_closures_code); +	builtin_closures_code = NewString(""); +	Clear(builtin_closures); +      } else { +	Printv(f_wrappers, "SWIGINTERN PyObject *", class_name, "_swigregister(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {\n", NIL); +	Printv(f_wrappers, "  PyObject *obj;\n", NIL); +	Printv(f_wrappers, "  if (!SWIG_Python_UnpackTuple(args, \"swigregister\", 1, 1, &obj)) return NULL;\n", NIL); + +	Printv(f_wrappers, +	       "  SWIG_TypeNewClientData(SWIGTYPE", SwigType_manglestr(ct), ", SWIG_NewClientData(obj));\n", "  return SWIG_Py_Void();\n", "}\n\n", NIL); +	String *cname = NewStringf("%s_swigregister", class_name); +	add_method(cname, cname, 0, 0, 1, 1, 1); +	Delete(cname); +      } +      Delete(smart); +      Delete(ct); +      Delete(realct); +      if (!have_constructor) { +	if (!builtin) +	  Printv(f_shadow_file, "\n", tab4, "def __init__(self, *args, **kwargs):\n", tab8, "raise AttributeError(\"", "No constructor defined", +		 (Getattr(n, "abstracts") ? " - class is abstract" : ""), "\")\n", NIL); +      } else if (!builtin) { + +	Printv(f_wrappers, "SWIGINTERN PyObject *", class_name, "_swiginit(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {\n", NIL); +	Printv(f_wrappers, "  return SWIG_Python_InitShadowInstance(args);\n", "}\n\n", NIL); +	String *cname = NewStringf("%s_swiginit", class_name); +	add_method(cname, cname, 0); +	Delete(cname); +      } +      if (!have_repr && !builtin) { +	/* Supply a repr method for this class  */ +	String *rname = SwigType_namestr(real_classname); +	Printv(f_shadow_file, tab4, "__repr__ = _swig_repr\n", NIL); +	Delete(rname); +      } + +      if (builtin) +	builtin_post_decl(f_builtins, n); + +      if (builtin_tp_init) { +	Delete(builtin_tp_init); +	builtin_tp_init = 0; +      } + +      if (!builtin) { +	/* Now emit methods */ +	Printv(f_shadow_file, f_shadow, NIL); +	Printf(f_shadow_file, "\n"); +	Printf(f_shadow_file, "# Register %s in %s:\n", class_name, module); +	Printf(f_shadow_file, "%s.%s_swigregister(%s)\n", module, class_name, class_name); +      } + +      shadow_indent = 0; +      if (Len(f_shadow_stubs) > 0) +	Printf(f_shadow_file, "%s\n", f_shadow_stubs); +      Clear(f_shadow_stubs); +    } + +    if (builtin) { +      Clear(class_members); +      Clear(builtin_getset); +      Clear(builtin_methods); +    } + +    /* Restore shadow file back to original version */ +    Delete(f_shadow); +    f_shadow = f_shadow_file; + +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * functionHandler()  -  Mainly overloaded for callback handling +   * ------------------------------------------------------------ */ + +  virtual int functionHandler(Node *n) { +    String *pcb = GetFlagAttr(n, "feature:python:callback"); +    if (pcb) { +      if (Strcmp(pcb, "1") == 0) { +	SetFlagAttr(n, "feature:callback", "%s_cb_ptr"); +      } else { +	SetFlagAttr(n, "feature:callback", pcb); +      } +      autodoc_l dlevel = autodoc_level(Getattr(n, "feature:autodoc")); +      if (dlevel != NO_AUTODOC && dlevel > TYPES_AUTODOC) { +	Setattr(n, "feature:autodoc", "1"); +      } +    } +    return Language::functionHandler(n); +  } + +  /* ------------------------------------------------------------ +   * memberfunctionHandler() +   * ------------------------------------------------------------ */ + +  virtual int memberfunctionHandler(Node *n) { +    String *symname = Getattr(n, "sym:name"); +    int oldshadow; + +    if (builtin) +      Swig_save("builtin_memberfunc", n, "python:argcount", NIL); + +    /* Create the default member function */ +    oldshadow = shadow;		/* Disable shadowing when wrapping member functions */ +    if (shadow) +      shadow = shadow | PYSHADOW_MEMBER; +    Language::memberfunctionHandler(n); +    shadow = oldshadow; + +    if (builtin && in_class) { +      // Can't use checkAttribute(n, "access", "public") because +      // "access" attr isn't set on %extend methods +      if (!checkAttribute(n, "access", "private") && strncmp(Char(symname), "operator ", 9) && !Getattr(class_members, symname)) { +	String *fullname = Swig_name_member(NSPACE_TODO, class_name, symname); +	String *wname = Swig_name_wrapper(fullname); +	Setattr(class_members, symname, n); +	int argcount = Getattr(n, "python:argcount") ? atoi(Char(Getattr(n, "python:argcount"))) : 2; +	String *ds = have_docstring(n) ? cdocstring(n, AUTODOC_METHOD) : NewString(""); +	if (check_kwargs(n)) { +	  // Cast via void(*)(void) to suppress GCC -Wcast-function-type +	  // warning.  Python should always call the function correctly, but +	  // the Python C API requires us to store it in function pointer of a +	  // different type. +	  Printf(builtin_methods, "  { \"%s\", (PyCFunction)(void(*)(void))%s, METH_VARARGS|METH_KEYWORDS, \"%s\" },\n", symname, wname, ds); +	} else if (argcount == 0) { +	  Printf(builtin_methods, "  { \"%s\", %s, METH_NOARGS, \"%s\" },\n", symname, wname, ds); +	} else if (argcount == 1) { +	  Printf(builtin_methods, "  { \"%s\", %s, METH_O, \"%s\" },\n", symname, wname, ds); +	} else { +	  Printf(builtin_methods, "  { \"%s\", %s, METH_VARARGS, \"%s\" },\n", symname, wname, ds); +	} +	Delete(fullname); +	Delete(wname); +	Delete(ds); +      } +    } + +    if (builtin) +      Swig_restore(n); + +    if (!Getattr(n, "sym:nextSibling")) { +      if (shadow && !builtin) { +	int fproxy = fastproxy; +	String *fullname = Swig_name_member(NSPACE_TODO, class_name, symname); +	if (Strcmp(symname, "__repr__") == 0) { +	  have_repr = 1; +	} +	if (Getattr(n, "feature:shadow")) { +	  String *pycode = indent_pythoncode(Getattr(n, "feature:shadow"), tab4, Getfile(n), Getline(n), "%feature(\"shadow\")"); +	  String *pyaction = NewStringf("%s.%s", module, fullname); +	  Replaceall(pycode, "$action", pyaction); +	  Delete(pyaction); +	  Printv(f_shadow, pycode, "\n", NIL); +	  Delete(pycode); +	  fproxy = 0; +	} else { +	  int allow_kwargs = (check_kwargs(n) && !Getattr(n, "sym:overloaded")) ? 1 : 0; +	  String *parms = make_pyParmList(n, true, false, allow_kwargs); +	  String *callParms = make_pyParmList(n, true, true, allow_kwargs); +	  if (!have_addtofunc(n)) { +	    if (!fastproxy || olddefs) { +	      Printv(f_shadow, "\n", tab4, "def ", symname, "(", parms, ")", returnTypeAnnotation(n), ":\n", NIL); +	      if (have_docstring(n)) +		Printv(f_shadow, tab8, docstring(n, AUTODOC_METHOD, tab8), "\n", NIL); +	      Printv(f_shadow, tab8, "return ", funcCall(fullname, callParms), "\n", NIL); +	    } +	  } else { +	    Printv(f_shadow, "\n", tab4, "def ", symname, "(", parms, ")", returnTypeAnnotation(n), ":\n", NIL); +	    if (have_docstring(n)) +	      Printv(f_shadow, tab8, docstring(n, AUTODOC_METHOD, tab8), "\n", NIL); +	    if (have_pythonprepend(n)) { +	      fproxy = 0; +	      Printv(f_shadow, indent_pythoncode(pythonprepend(n), tab8, Getfile(n), Getline(n), "%pythonprepend or %feature(\"pythonprepend\")"), "\n", NIL); +	    } +	    if (have_pythonappend(n)) { +	      fproxy = 0; +	      Printv(f_shadow, tab8, "val = ", funcCall(fullname, callParms), "\n", NIL); +	      Printv(f_shadow, indent_pythoncode(pythonappend(n), tab8, Getfile(n), Getline(n), "%pythonappend or %feature(\"pythonappend\")"), "\n", NIL); +	      Printv(f_shadow, tab8, "return val\n\n", NIL); +	    } else { +	      Printv(f_shadow, tab8, "return ", funcCall(fullname, callParms), "\n\n", NIL); +	    } +	  } +	} +	if (fproxy) { +	  Printf(f_shadow, tab4); +	  Printf(f_shadow, "%s = _swig_new_instance_method(%s.%s)\n", symname, module, Swig_name_member(NSPACE_TODO, class_name, symname)); +	} +	Delete(fullname); +      } +    } +    return SWIG_OK; +  } + + +  /* ------------------------------------------------------------ +   * staticmemberfunctionHandler() +   * ------------------------------------------------------------ */ + +  virtual int staticmemberfunctionHandler(Node *n) { +    String *symname = Getattr(n, "sym:name"); +    if (builtin && in_class) { +      Swig_save("builtin_memberconstantHandler", n, "pybuiltin:symname", NIL); +      Setattr(n, "pybuiltin:symname", symname); +    } +    Language::staticmemberfunctionHandler(n); +    if (builtin && in_class) { +      Swig_restore(n); +    } + +    int kw = (check_kwargs(n) && !Getattr(n, "sym:overloaded")) ? 1 : 0; +    if (builtin && in_class) { +      if ((GetFlagAttr(n, "feature:extend") || checkAttribute(n, "access", "public")) +	  && !Getattr(class_members, symname)) { +	String *fullname = Swig_name_member(NSPACE_TODO, class_name, symname); +	String *wname = Swig_name_wrapper(fullname); +	Setattr(class_members, symname, n); +	int funpack = fastunpack && !Getattr(n, "sym:overloaded"); +	String *pyflags = NewString("METH_STATIC|"); +	int argcount = Getattr(n, "python:argcount") ? atoi(Char(Getattr(n, "python:argcount"))) : 2; +	if (funpack && argcount == 0) +	  Append(pyflags, "METH_NOARGS"); +	else if (funpack && argcount == 1) +	  Append(pyflags, "METH_O"); +	else +	  Append(pyflags, kw ? "METH_VARARGS|METH_KEYWORDS" : "METH_VARARGS"); +	// Cast via void(*)(void) to suppress GCC -Wcast-function-type warning. +	// Python should always call the function correctly, but the Python C +	// API requires us to store it in function pointer of a different type. +	if (have_docstring(n)) { +	  String *ds = cdocstring(n, AUTODOC_STATICFUNC); +	  Printf(builtin_methods, "  { \"%s\", (PyCFunction)(void(*)(void))%s, %s, \"%s\" },\n", symname, wname, pyflags, ds); +	  Delete(ds); +	} else if (Getattr(n, "feature:callback")) { +	  String *ds = NewStringf("swig_ptr: %s", Getattr(n, "feature:callback:name")); +	  Printf(builtin_methods, "  { \"%s\", (PyCFunction)(void(*)(void))%s, %s, \"%s\" },\n", symname, wname, pyflags, ds); +	  Delete(ds); +	  have_builtin_static_member_method_callback = true; +	} else { +	  Printf(builtin_methods, "  { \"%s\", (PyCFunction)(void(*)(void))%s, %s, \"\" },\n", symname, wname, pyflags); +	} +	Delete(fullname); +	Delete(wname); +	Delete(pyflags); +      } +      return SWIG_OK; +    } + +    if (Getattr(n, "sym:nextSibling")) { +      return SWIG_OK; +    } + +    if (shadow) { +      String *staticfunc_name = NewString(fastproxy ? "_swig_new_static_method" : "staticmethod"); +      bool fast = (fastproxy && !have_addtofunc(n)) || Getattr(n, "feature:callback"); +      if (!fast || olddefs) { +	String *parms = make_pyParmList(n, false, false, kw); +	String *callParms = make_pyParmList(n, false, true, kw); +	Printv(f_shadow, "\n", tab4, "@staticmethod", NIL); +	Printv(f_shadow, "\n", tab4, "def ", symname, "(", parms, ")", returnTypeAnnotation(n), ":\n", NIL); +	if (have_docstring(n)) +	  Printv(f_shadow, tab8, docstring(n, AUTODOC_STATICFUNC, tab8), "\n", NIL); +	if (have_pythonprepend(n)) +	  Printv(f_shadow, indent_pythoncode(pythonprepend(n), tab8, Getfile(n), Getline(n), "%pythonprepend or %feature(\"pythonprepend\")"), "\n", NIL); +	if (have_pythonappend(n)) { +	  Printv(f_shadow, tab8, "val = ", funcCall(Swig_name_member(NSPACE_TODO, class_name, symname), callParms), "\n", NIL); +	  Printv(f_shadow, indent_pythoncode(pythonappend(n), tab8, Getfile(n), Getline(n), "%pythonappend or %feature(\"pythonappend\")"), "\n", NIL); +	  Printv(f_shadow, tab8, "return val\n", NIL); +	} else { +	  Printv(f_shadow, tab8, "return ", funcCall(Swig_name_member(NSPACE_TODO, class_name, symname), callParms), "\n", NIL); +	} +      } + +      // Below may result in a 2nd definition of the method when -olddefs is used. The Python interpreter will use the second definition as it overwrites the first. +      if (fast) { +	Printv(f_shadow, tab4, symname, " = ", staticfunc_name, "(", module, ".", Swig_name_member(NSPACE_TODO, class_name, symname), +	       ")\n", NIL); +      } +      Delete(staticfunc_name); +    } +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * constructorDeclaration() +   * ------------------------------------------------------------ */ + +  virtual int constructorHandler(Node *n) { +    String *symname = Getattr(n, "sym:name"); +    int oldshadow = shadow; +    int use_director = Swig_directorclass(n); + +    /* +     * If we're wrapping the constructor of a C++ director class, prepend a new parameter +     * to receive the scripting language object (e.g. 'self') +     * +     */ +    Swig_save("python:constructorHandler", n, "parms", NIL); +    if (use_director) { +      Parm *parms = Getattr(n, "parms"); +      Parm *self; +      String *name = NewString("self"); +      String *type = NewString("PyObject"); +      SwigType_add_pointer(type); +      self = NewParm(type, name, n); +      Delete(type); +      Delete(name); +      Setattr(self, "lname", "O"); +      if (parms) +	set_nextSibling(self, parms); +      Setattr(n, "parms", self); +      Setattr(n, "wrap:self", "1"); +      Setattr(n, "hidden", "1"); +      Delete(self); +    } + +    if (shadow) +      shadow = shadow | PYSHADOW_MEMBER; +    Language::constructorHandler(n); +    shadow = oldshadow; + +    Delattr(n, "wrap:self"); +    Swig_restore(n); + +    if (!Getattr(n, "sym:nextSibling")) { +      if (shadow) { +	int allow_kwargs = (check_kwargs(n) && (!Getattr(n, "sym:overloaded"))) ? 1 : 0; +	int handled_as_init = 0; +	if (!have_constructor) { +	  String *nname = Getattr(n, "sym:name"); +	  String *sname = Getattr(getCurrentClass(), "sym:name"); +	  String *cname = Swig_name_construct(NSPACE_TODO, sname); +	  handled_as_init = (Strcmp(nname, sname) == 0) || (Strcmp(nname, cname) == 0); +	  Delete(cname); +	} + +	String *subfunc = Swig_name_construct(NSPACE_TODO, symname); +	if (!have_constructor && handled_as_init) { +	  if (!builtin) { +	    if (Getattr(n, "feature:shadow")) { +	      String *pycode = indent_pythoncode(Getattr(n, "feature:shadow"), tab4, Getfile(n), Getline(n), "%feature(\"shadow\")"); +	      String *pyaction = NewStringf("%s.%s", module, subfunc); +	      Replaceall(pycode, "$action", pyaction); +	      Delete(pyaction); +	      Printv(f_shadow, pycode, "\n", NIL); +	      Delete(pycode); +	    } else { +	      String *pass_self = NewString(""); +	      Node *parent = Swig_methodclass(n); +	      String *classname = Swig_class_name(parent); +	      String *rclassname = Swig_class_name(getCurrentClass()); +	      assert(rclassname); +	      (void)rclassname; + +	      String *parms = make_pyParmList(n, true, false, allow_kwargs); +	      /* Pass 'self' only if using director */ +	      String *callParms = make_pyParmList(n, false, true, allow_kwargs, true); + +	      if (use_director) { +		Insert(callParms, 0, "_self, "); +		Printv(pass_self, tab8, NIL); +		Printf(pass_self, "if self.__class__ == %s:\n", classname); +		//Printv(pass_self, tab8, tab4, "args = (None,) + args\n", tab8, "else:\n", tab8, tab4, "args = (self,) + args\n", NIL); +		Printv(pass_self, tab8, tab4, "_self = None\n", tab8, "else:\n", tab8, tab4, "_self = self\n", NIL); +	      } + +	      Printv(f_shadow, "\n", tab4, "def __init__(", parms, ")", returnTypeAnnotation(n), ":\n", NIL); +	      if (have_docstring(n)) +		Printv(f_shadow, tab8, docstring(n, AUTODOC_CTOR, tab8), "\n", NIL); +	      if (have_pythonprepend(n)) +		Printv(f_shadow, indent_pythoncode(pythonprepend(n), tab8, Getfile(n), Getline(n), "%pythonprepend or %feature(\"pythonprepend\")"), "\n", NIL); +	      Printv(f_shadow, pass_self, NIL); +	      Printv(f_shadow, tab8, module, ".", class_name, "_swiginit(self, ", funcCall(subfunc, callParms), ")\n", NIL); +	      if (have_pythonappend(n)) +		Printv(f_shadow, indent_pythoncode(pythonappend(n), tab8, Getfile(n), Getline(n), "%pythonappend or %feature(\"pythonappend\")"), "\n\n", NIL); +	      Delete(pass_self); +	    } +	    have_constructor = 1; +	  } +	} else { +	  /* Hmmm. We seem to be creating a different constructor.  We're just going to create a +	     function for it. */ +	  if (!builtin) { +	    if (Getattr(n, "feature:shadow")) { +	      String *pycode = indent_pythoncode(Getattr(n, "feature:shadow"), "", Getfile(n), Getline(n), "%feature(\"shadow\")"); +	      String *pyaction = NewStringf("%s.%s", module, subfunc); +	      Replaceall(pycode, "$action", pyaction); +	      Delete(pyaction); +	      Printv(f_shadow_stubs, pycode, "\n", NIL); +	      Delete(pycode); +	    } else { +	      String *parms = make_pyParmList(n, false, false, allow_kwargs); +	      String *callParms = make_pyParmList(n, false, true, allow_kwargs); + +	      Printv(f_shadow_stubs, "\ndef ", symname, "(", parms, ")", returnTypeAnnotation(n), ":\n", NIL); +	      if (have_docstring(n)) +		Printv(f_shadow_stubs, tab4, docstring(n, AUTODOC_CTOR, tab4), "\n", NIL); +	      if (have_pythonprepend(n)) +		Printv(f_shadow_stubs, indent_pythoncode(pythonprepend(n), tab4, Getfile(n), Getline(n), "%pythonprepend or %feature(\"pythonprepend\")"), "\n", NIL); +	      Printv(f_shadow_stubs, tab4, "val = ", funcCall(subfunc, callParms), "\n", NIL); +	      if (have_pythonappend(n)) +		Printv(f_shadow_stubs, indent_pythoncode(pythonappend(n), tab4, Getfile(n), Getline(n), "%pythonappend or %feature(\"pythonappend\")"), "\n", NIL); +	      Printv(f_shadow_stubs, tab4, "return val\n", NIL); +	    } +	  } else { +	    Printf(f_shadow_stubs, "%s = %s\n", symname, subfunc); +	  } +	} +	Delete(subfunc); +      } +    } +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * destructorHandler() +   * ------------------------------------------------------------ */ + +  virtual int destructorHandler(Node *n) { +    String *symname = Getattr(n, "sym:name"); +    int oldshadow = shadow; + +    if (builtin && in_class) { +      Node *cls = Swig_methodclass(n); +      // Use the destructor for the tp_dealloc slot unless a user overrides it with another method +      if (!Getattr(cls, "feature:python:tp_dealloc")) { +	Setattr(n, "feature:python:slot", "tp_dealloc"); +	Setattr(n, "feature:python:slot:functype", "destructor"); +      } +    } + +    if (shadow) +      shadow = shadow | PYSHADOW_MEMBER; +    //Setattr(n,"emit:dealloc","1"); +    Language::destructorHandler(n); +    shadow = oldshadow; + +    if (shadow) { +      if (Getattr(n, "feature:shadow")) { +	String *pycode = indent_pythoncode(Getattr(n, "feature:shadow"), tab4, Getfile(n), Getline(n), "%feature(\"shadow\")"); +	String *pyaction = NewStringf("%s.%s", module, Swig_name_destroy(NSPACE_TODO, symname)); +	Replaceall(pycode, "$action", pyaction); +	Delete(pyaction); +	Printv(f_shadow, pycode, "\n", NIL); +	Delete(pycode); +      } else { +	Printv(f_shadow, tab4, "__swig_destroy__ = ", module, ".", Swig_name_destroy(NSPACE_TODO, symname), "\n", NIL); +	if (!have_pythonprepend(n) && !have_pythonappend(n)) { +	  return SWIG_OK; +	} +	Printv(f_shadow, tab4, "def __del__(self):\n", NIL); +	if (have_docstring(n)) +	  Printv(f_shadow, tab8, docstring(n, AUTODOC_DTOR, tab8), "\n", NIL); +	if (have_pythonprepend(n)) +	  Printv(f_shadow, indent_pythoncode(pythonprepend(n), tab8, Getfile(n), Getline(n), "%pythonprepend or %feature(\"pythonprepend\")"), "\n", NIL); +	if (have_pythonappend(n)) +	  Printv(f_shadow, indent_pythoncode(pythonappend(n), tab8, Getfile(n), Getline(n), "%pythonappend or %feature(\"pythonappend\")"), "\n", NIL); +	Printv(f_shadow, tab8, "pass\n", NIL); +	Printv(f_shadow, "\n", NIL); +      } +    } +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * membervariableHandler() +   * ------------------------------------------------------------ */ + +  virtual int membervariableHandler(Node *n) { +    String *symname = Getattr(n, "sym:name"); + +    int oldshadow = shadow; +    if (shadow) +      shadow = shadow | PYSHADOW_MEMBER; +    Language::membervariableHandler(n); +    shadow = oldshadow; + +    if (shadow && !builtin) { +      String *mname = Swig_name_member(NSPACE_TODO, class_name, symname); +      String *setname = Swig_name_set(NSPACE_TODO, mname); +      String *getname = Swig_name_get(NSPACE_TODO, mname); +      int assignable = is_assignable(n); +      String *variable_annotation = variableAnnotation(n); +      Printv(f_shadow, tab4, symname, variable_annotation, " = property(", module, ".", getname, NIL); +      if (assignable) +	Printv(f_shadow, ", ", module, ".", setname, NIL); +      if (have_docstring(n)) { +	String *s = docstring(n, AUTODOC_VAR, tab4); +	if (Len(s)) +	  Printv(f_shadow, ", doc=", s, NIL); +      } +      Printv(f_shadow, ")\n", NIL); +      Delete(variable_annotation); +      Delete(mname); +      Delete(setname); +      Delete(getname); +    } + +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * staticmembervariableHandler() +   * ------------------------------------------------------------ */ + +  virtual int staticmembervariableHandler(Node *n) { +    Swig_save("builtin_staticmembervariableHandler", n, "builtin_symname", NIL); +    Language::staticmembervariableHandler(n); +    Swig_restore(n); + +    if (GetFlag(n, "wrappedasconstant")) +      return SWIG_OK; + +    String *symname = Getattr(n, "sym:name"); + +    if (shadow) { +      if (!builtin && GetFlag(n, "hasconsttype")) { +	String *mname = Swig_name_member(NSPACE_TODO, class_name, symname); +	Printf(f_shadow_stubs, "%s.%s = %s.%s.%s\n", class_name, symname, module, global_name, mname); +	Delete(mname); +      } else { +	String *mname = Swig_name_member(NSPACE_TODO, class_name, symname); +	String *getname = Swig_name_get(NSPACE_TODO, mname); +	String *wrapgetname = Swig_name_wrapper(getname); +	String *vargetname = NewStringf("Swig_var_%s", getname); +	String *setname = Swig_name_set(NSPACE_TODO, mname); +	String *wrapsetname = Swig_name_wrapper(setname); +	String *varsetname = NewStringf("Swig_var_%s", setname); + +	Wrapper *f = NewWrapper(); +	Printv(f->def, "SWIGINTERN PyObject *", wrapgetname, "(PyObject *SWIGUNUSEDPARM(self), PyObject *SWIGUNUSEDPARM(args)) {", NIL); +	Printv(f->code, "  return ", vargetname, "();\n", NIL); +	Append(f->code, "}\n"); +	add_method(getname, wrapgetname, 0); +	Wrapper_print(f, f_wrappers); +	DelWrapper(f); +	int assignable = is_assignable(n); +	if (assignable) { +	  int funpack = fastunpack; +	  Wrapper *f = NewWrapper(); +	  Printv(f->def, "SWIGINTERN PyObject *", wrapsetname, "(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {", NIL); +	  Wrapper_add_local(f, "res", "int res"); +	  if (!funpack) { +	    Wrapper_add_local(f, "value", "PyObject *value"); +	    Append(f->code, "if (!PyArg_ParseTuple(args, \"O:set\", &value)) return NULL;\n"); +	  } +	  Printf(f->code, "res = %s(%s);\n", varsetname, funpack ? "args" : "value"); +	  Append(f->code, "return !res ? SWIG_Py_Void() : NULL;\n"); +	  Append(f->code, "}\n"); +	  Wrapper_print(f, f_wrappers); +	  add_method(setname, wrapsetname, 0, 0, funpack, 1, 1); +	  DelWrapper(f); +	} +	if (!builtin) { +	  Printv(f_shadow, tab4, symname, " = property(", module, ".", getname, NIL); +	  if (assignable) +	    Printv(f_shadow, ", ", module, ".", setname, NIL); +	  if (have_docstring(n)) { +	    String *s = docstring(n, AUTODOC_VAR, tab4); +	    if (Len(s)) +	      Printv(f_shadow, ", doc=", s, NIL); +	  } +	  Printv(f_shadow, ")\n", NIL); +	} +	String *getter = Getattr(n, "pybuiltin:getter"); +	String *setter = Getattr(n, "pybuiltin:setter"); +	Hash *h = NULL; +	if (getter || setter) { +	  h = Getattr(builtin_getset, symname); +	  if (!h) { +	    h = NewHash(); +	    Setattr(h, "static", "1"); +	    Setattr(builtin_getset, symname, h); +	  } +	} +	if (getter) +	  Setattr(h, "getter", getter); +	if (setter) +	  Setattr(h, "setter", setter); +	if (h) +	  Delete(h); +	Delete(mname); +	Delete(getname); +	Delete(wrapgetname); +	Delete(vargetname); +	Delete(setname); +	Delete(wrapsetname); +	Delete(varsetname); +      } +    } +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * memberconstantHandler() +   * ------------------------------------------------------------ */ + +  virtual int memberconstantHandler(Node *n) { +    String *symname = Getattr(n, "sym:name"); +    if (builtin && in_class) { +      Swig_save("builtin_memberconstantHandler", n, "pybuiltin:symname", NIL); +      Setattr(n, "pybuiltin:symname", symname); +    } +    int oldshadow = shadow; +    if (shadow) +      shadow = shadow | PYSHADOW_MEMBER; +    Language::memberconstantHandler(n); +    shadow = oldshadow; + +    if (builtin && in_class) { +      Swig_restore(n); +    } else if (shadow) { +      Printv(f_shadow, tab4, symname, " = ", module, ".", Swig_name_member(NSPACE_TODO, class_name, symname), "\n", NIL); +      if (have_docstring(n)) +	Printv(f_shadow, tab4, docstring(n, AUTODOC_CONST, tab4), "\n", NIL); +    } +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * insertDirective() +   * +   * Hook for %insert directive.   We're going to look for special %shadow inserts +   * as a special case so we can do indenting correctly +   * ------------------------------------------------------------ */ + +  virtual int insertDirective(Node *n) { +    String *code = Getattr(n, "code"); +    String *section = Getattr(n, "section"); + +    if (!ImportMode && (Cmp(section, "python") == 0 || Cmp(section, "shadow") == 0)) { +      if (shadow) { +	String *pycode = indent_pythoncode(code, shadow_indent, Getfile(n), Getline(n), "%pythoncode or %insert(\"python\") block"); +	Printv(f_shadow, pycode, NIL); +	Delete(pycode); +      } +    } else if (!ImportMode && (Cmp(section, "pythonbegin") == 0)) { +      if (shadow) { +	String *pycode = indent_pythoncode(code, "", Getfile(n), Getline(n), "%pythonbegin or %insert(\"pythonbegin\") block"); +	Printv(f_shadow_begin, pycode, NIL); +	Delete(pycode); +      } +    } else { +      Language::insertDirective(n); +    } +    return SWIG_OK; +  } + +  virtual String *runtimeCode() { +    String *s = NewString(""); +    String *shead = Swig_include_sys("pyhead.swg"); +    if (!shead) { +      Printf(stderr, "*** Unable to open 'pyhead.swg'\n"); +    } else { +      Append(s, shead); +      Delete(shead); +    } +    String *serrors = Swig_include_sys("pyerrors.swg"); +    if (!serrors) { +      Printf(stderr, "*** Unable to open 'pyerrors.swg'\n"); +    } else { +      Append(s, serrors); +      Delete(serrors); +    } +    String *sthread = Swig_include_sys("pythreads.swg"); +    if (!sthread) { +      Printf(stderr, "*** Unable to open 'pythreads.swg'\n"); +    } else { +      Append(s, sthread); +      Delete(sthread); +    } +    String *sapi = Swig_include_sys("pyapi.swg"); +    if (!sapi) { +      Printf(stderr, "*** Unable to open 'pyapi.swg'\n"); +    } else { +      Append(s, sapi); +      Delete(sapi); +    } +    String *srun = Swig_include_sys("pyrun.swg"); +    if (!srun) { +      Printf(stderr, "*** Unable to open 'pyrun.swg'\n"); +    } else { +      Append(s, srun); +      Delete(srun); +    } +    return s; +  } + +  virtual String *defaultExternalRuntimeFilename() { +    return NewString("swigpyrun.h"); +  } + +  /*---------------------------------------------------------------------- +   * kwargsSupport() +   *--------------------------------------------------------------------*/ + +  bool kwargsSupport() const { +    return true; +  } +}; + +/* --------------------------------------------------------------- + * classDirectorMethod() + * + * Emit a virtual director method to pass a method call on to the + * underlying Python object. + * + * ** Moved it here due to internal error on gcc-2.96 ** + * --------------------------------------------------------------- */ +int PYTHON::classDirectorMethods(Node *n) { +  director_method_index = 0; +  return Language::classDirectorMethods(n); +} + + +int PYTHON::classDirectorMethod(Node *n, Node *parent, String *super) { +  int is_void = 0; +  int is_pointer = 0; +  String *decl = Getattr(n, "decl"); +  String *name = Getattr(n, "name"); +  String *classname = Getattr(parent, "sym:name"); +  String *c_classname = Getattr(parent, "name"); +  String *symname = Getattr(n, "sym:name"); +  String *declaration = NewString(""); +  ParmList *l = Getattr(n, "parms"); +  Wrapper *w = NewWrapper(); +  String *tm; +  String *wrap_args = NewString(""); +  String *returntype = Getattr(n, "type"); +  String *value = Getattr(n, "value"); +  String *storage = Getattr(n, "storage"); +  bool pure_virtual = false; +  int status = SWIG_OK; +  int idx; +  bool ignored_method = GetFlag(n, "feature:ignore") ? true : false; + +  if (builtin) { +    // Rename any wrapped parameters called 'self' as the generated code contains a variable with same name +    Parm *p; +    for (p = l; p; p = nextSibling(p)) { +      String *arg = Getattr(p, "name"); +      if (arg && Cmp(arg, "self") == 0) +	Delattr(p, "name"); +    } +  } + +  if (Cmp(storage, "virtual") == 0) { +    if (Cmp(value, "0") == 0) { +      pure_virtual = true; +    } +  } + +  /* determine if the method returns a pointer */ +  is_pointer = SwigType_ispointer_return(decl); +  is_void = (!Cmp(returntype, "void") && !is_pointer); + +  /* virtual method definition */ +  String *target; +  String *pclassname = NewStringf("SwigDirector_%s", classname); +  String *qualified_name = NewStringf("%s::%s", pclassname, name); +  SwigType *rtype = Getattr(n, "conversion_operator") ? 0 : Getattr(n, "classDirectorMethods:type"); +  target = Swig_method_decl(rtype, decl, qualified_name, l, 0); +  Printf(w->def, "%s", target); +  Delete(qualified_name); +  Delete(target); +  /* header declaration */ +  target = Swig_method_decl(rtype, decl, name, l, 1); +  Printf(declaration, "    virtual %s", target); +  Delete(target); + +  // Get any exception classes in the throws typemap +  if (Getattr(n, "noexcept")) { +    Append(w->def, " noexcept"); +    Append(declaration, " noexcept"); +  } +  ParmList *throw_parm_list = 0; +  if ((throw_parm_list = Getattr(n, "throws")) || Getattr(n, "throw")) { +    Parm *p; +    int gencomma = 0; + +    Append(w->def, " throw("); +    Append(declaration, " throw("); + +    if (throw_parm_list) +      Swig_typemap_attach_parms("throws", throw_parm_list, 0); +    for (p = throw_parm_list; p; p = nextSibling(p)) { +      if (Getattr(p, "tmap:throws")) { +	if (gencomma++) { +	  Append(w->def, ", "); +	  Append(declaration, ", "); +	} +	String *str = SwigType_str(Getattr(p, "type"), 0); +	Append(w->def, str); +	Append(declaration, str); +	Delete(str); +      } +    } + +    Append(w->def, ")"); +    Append(declaration, ")"); +  } + +  Append(w->def, " {"); +  Append(declaration, ";\n"); + +  /* declare method return value +   * if the return value is a reference or const reference, a specialized typemap must +   * handle it, including declaration of c_result ($result). +   */ +  if (!is_void && (!ignored_method || pure_virtual)) { +    if (!SwigType_isclass(returntype)) { +      if (!(SwigType_ispointer(returntype) || SwigType_isreference(returntype))) { +	String *construct_result = NewStringf("= SwigValueInit< %s >()", SwigType_lstr(returntype, 0)); +	Wrapper_add_localv(w, "c_result", SwigType_lstr(returntype, "c_result"), construct_result, NIL); +	Delete(construct_result); +      } else { +	Wrapper_add_localv(w, "c_result", SwigType_lstr(returntype, "c_result"), "= 0", NIL); +      } +    } else { +      String *cres = SwigType_lstr(returntype, "c_result"); +      Printf(w->code, "%s;\n", cres); +      Delete(cres); +    } +  } + +  if (builtin) { +    Printv(w->code, "PyObject *self = NULL;\n", NIL); +    Printv(w->code, "(void)self;\n", NIL); +  } + +  if (ignored_method) { +    if (!pure_virtual) { +      if (!is_void) +	Printf(w->code, "return "); +      String *super_call = Swig_method_call(super, l); +      Printf(w->code, "%s;\n", super_call); +      Delete(super_call); +    } else { +      Printf(w->code, "Swig::DirectorPureVirtualException::raise(\"Attempted to invoke pure virtual method %s::%s\");\n", SwigType_namestr(c_classname), +	     SwigType_namestr(name)); +    } +  } else { +    /* attach typemaps to arguments (C/C++ -> Python) */ +    String *arglist = NewString(""); +    String *parse_args = NewString(""); + +    Swig_director_parms_fixup(l); + +    /* remove the wrapper 'w' since it was producing spurious temps */ +    Swig_typemap_attach_parms("in", l, 0); +    Swig_typemap_attach_parms("directorin", l, w); +    Swig_typemap_attach_parms("directorargout", l, w); + +    Parm *p; +    char source[256]; + +    int outputs = 0; +    if (!is_void) +      outputs++; + +    /* build argument list and type conversion string */ +    idx = 0; +    p = l; +    int use_parse = 0; +    while (p) { +      if (checkAttribute(p, "tmap:in:numinputs", "0")) { +	p = Getattr(p, "tmap:in:next"); +	continue; +      } + +      /* old style?  caused segfaults without the p!=0 check +         in the for() condition, and seems dangerous in the +         while loop as well. +         while (Getattr(p, "tmap:ignore")) { +         p = Getattr(p, "tmap:ignore:next"); +         } +       */ + +      if (Getattr(p, "tmap:directorargout") != 0) +	outputs++; + +      String *pname = Getattr(p, "name"); +      String *ptype = Getattr(p, "type"); + +      Putc(',', arglist); +      if ((tm = Getattr(p, "tmap:directorin")) != 0) { +	String *parse = Getattr(p, "tmap:directorin:parse"); +	if (!parse) { +	  sprintf(source, "obj%d", idx++); +	  String *input = NewString(source); +	  Setattr(p, "emit:directorinput", input); +	  Replaceall(tm, "$input", input); +	  Delete(input); +	  Replaceall(tm, "$owner", "0"); +	  /* Wrapper_add_localv(w, source, "swig::SwigVar_PyObject", source, "= 0", NIL); */ +	  Printv(wrap_args, "swig::SwigVar_PyObject ", source, ";\n", NIL); + +	  Printv(wrap_args, tm, "\n", NIL); +	  Printv(arglist, "(PyObject *)", source, NIL); +	  Putc('O', parse_args); +	} else { +	  use_parse = 1; +	  Append(parse_args, parse); +	  Setattr(p, "emit:directorinput", pname); +	  Replaceall(tm, "$input", pname); +	  Replaceall(tm, "$owner", "0"); +	  if (Len(tm) == 0) +	    Append(tm, pname); +	  Append(arglist, tm); +	} +	p = Getattr(p, "tmap:directorin:next"); +	continue; +      } else if (Cmp(ptype, "void")) { +	/* special handling for pointers to other C++ director classes. +	 * ideally this would be left to a typemap, but there is currently no +	 * way to selectively apply the dynamic_cast<> to classes that have +	 * directors.  in other words, the type "SwigDirector_$1_lname" only exists +	 * for classes with directors.  we avoid the problem here by checking +	 * module.wrap::directormap, but it's not clear how to get a typemap to +	 * do something similar.  perhaps a new default typemap (in addition +	 * to SWIGTYPE) called DIRECTORTYPE? +	 */ +	if (SwigType_ispointer(ptype) || SwigType_isreference(ptype)) { +	  Node *module = Getattr(parent, "module"); +	  Node *target = Swig_directormap(module, ptype); +	  sprintf(source, "obj%d", idx++); +	  String *nonconst = 0; +	  /* strip pointer/reference --- should move to Swig/stype.c */ +	  String *nptype = NewString(Char(ptype) + 2); +	  /* name as pointer */ +	  String *ppname = Copy(pname); +	  if (SwigType_isreference(ptype)) { +	    Insert(ppname, 0, "&"); +	  } +	  /* if necessary, cast away const since Python doesn't support it! */ +	  if (SwigType_isconst(nptype)) { +	    nonconst = NewStringf("nc_tmp_%s", pname); +	    String *nonconst_i = NewStringf("= const_cast< %s >(%s)", SwigType_lstr(ptype, 0), ppname); +	    Wrapper_add_localv(w, nonconst, SwigType_lstr(ptype, 0), nonconst, nonconst_i, NIL); +	    Delete(nonconst_i); +	    Swig_warning(WARN_LANG_DISCARD_CONST, input_file, line_number, +			 "Target language argument '%s' discards const in director method %s::%s.\n", +			 SwigType_str(ptype, pname), SwigType_namestr(c_classname), SwigType_namestr(name)); +	  } else { +	    nonconst = Copy(ppname); +	  } +	  Delete(nptype); +	  Delete(ppname); +	  String *mangle = SwigType_manglestr(ptype); +	  if (target) { +	    String *director = NewStringf("director_%s", mangle); +	    Wrapper_add_localv(w, director, "Swig::Director *", director, "= 0", NIL); +	    Wrapper_add_localv(w, source, "swig::SwigVar_PyObject", source, "= 0", NIL); +	    Printf(wrap_args, "%s = SWIG_DIRECTOR_CAST(%s);\n", director, nonconst); +	    Printf(wrap_args, "if (!%s) {\n", director); +	    Printf(wrap_args, "%s = SWIG_InternalNewPointerObj(%s, SWIGTYPE%s, 0);\n", source, nonconst, mangle); +	    Append(wrap_args, "} else {\n"); +	    Printf(wrap_args, "%s = %s->swig_get_self();\n", source, director); +	    Printf(wrap_args, "Py_INCREF((PyObject *)%s);\n", source); +	    Append(wrap_args, "}\n"); +	    Delete(director); +	    Printv(arglist, source, NIL); +	  } else { +	    Wrapper_add_localv(w, source, "swig::SwigVar_PyObject", source, "= 0", NIL); +	    Printf(wrap_args, "%s = SWIG_InternalNewPointerObj(%s, SWIGTYPE%s, 0);\n", source, nonconst, mangle); +	    //Printf(wrap_args, "%s = SWIG_NewPointerObj(%s, SWIGTYPE_p_%s, 0);\n", +	    //       source, nonconst, base); +	    Printv(arglist, source, NIL); +	  } +	  Putc('O', parse_args); +	  Delete(mangle); +	  Delete(nonconst); +	} else { +	  Swig_warning(WARN_TYPEMAP_DIRECTORIN_UNDEF, input_file, line_number, +		       "Unable to use type %s as a function argument in director method %s::%s (skipping method).\n", SwigType_str(ptype, 0), +		       SwigType_namestr(c_classname), SwigType_namestr(name)); +	  status = SWIG_NOWRAP; +	  break; +	} +      } +      p = nextSibling(p); +    } + +    /* add the method name as a PyString */ +    String *pyname = Getattr(n, "sym:name"); + +    int allow_thread = threads_enable(n); + +    if (allow_thread) { +      thread_begin_block(n, w->code); +      Append(w->code, "{\n"); +    } + +    /* wrap complex arguments to PyObjects */ +    Printv(w->code, wrap_args, NIL); + +    /* pass the method call on to the Python object */ +    if (dirprot_mode() && !is_public(n)) { +      Printf(w->code, "swig_set_inner(\"%s\", true);\n", name); +    } + + +    Append(w->code, "if (!swig_get_self()) {\n"); +    Printf(w->code, "  Swig::DirectorException::raise(\"'self' uninitialized, maybe you forgot to call %s.__init__.\");\n", classname); +    Append(w->code, "}\n"); +    Append(w->code, "#if defined(SWIG_PYTHON_DIRECTOR_VTABLE)\n"); +    Printf(w->code, "const size_t swig_method_index = %d;\n", director_method_index++); +    Printf(w->code, "const char *const swig_method_name = \"%s\";\n", pyname); + +    Append(w->code, "PyObject *method = swig_get_method(swig_method_index, swig_method_name);\n"); +    if (Len(parse_args) > 0) { +      if (use_parse) { +	Printf(w->code, "swig::SwigVar_PyObject %s = PyObject_CallFunction(method, (char *)\"(%s)\" %s);\n", Swig_cresult_name(), parse_args, arglist); +      } else { +	Printf(w->code, "swig::SwigVar_PyObject %s = PyObject_CallFunctionObjArgs(method %s, NULL);\n", Swig_cresult_name(), arglist); +      } +    } else { +      Append(w->code, "swig::SwigVar_PyObject args = PyTuple_New(0);\n"); +      Printf(w->code, "swig::SwigVar_PyObject %s = PyObject_Call(method, (PyObject *) args, NULL);\n", Swig_cresult_name()); +    } +    Append(w->code, "#else\n"); +    if (Len(parse_args) > 0) { +      if (use_parse) { +	Printf(w->code, "swig::SwigVar_PyObject %s = PyObject_CallMethod(swig_get_self(), (char *)\"%s\", (char *)\"(%s)\" %s);\n", Swig_cresult_name(), pyname, parse_args, arglist); +      } else { +	Printf(w->code, "swig::SwigVar_PyObject swig_method_name = SWIG_Python_str_FromChar(\"%s\");\n", pyname); +	Printf(w->code, "swig::SwigVar_PyObject %s = PyObject_CallMethodObjArgs(swig_get_self(), (PyObject *) swig_method_name %s, NULL);\n", Swig_cresult_name(), arglist); +      } +    } else { +      Printf(w->code, "swig::SwigVar_PyObject swig_method_name = SWIG_Python_str_FromChar(\"%s\");\n", pyname); +      Printf(w->code, "swig::SwigVar_PyObject %s = PyObject_CallMethodObjArgs(swig_get_self(), (PyObject *) swig_method_name, NULL);\n", Swig_cresult_name()); +    } +    Append(w->code, "#endif\n"); + +    if (dirprot_mode() && !is_public(n)) +      Printf(w->code, "swig_set_inner(\"%s\", false);\n", name); + +    /* exception handling */ +    tm = Swig_typemap_lookup("director:except", n, Swig_cresult_name(), 0); +    if (!tm) { +      tm = Getattr(n, "feature:director:except"); +      if (tm) +	tm = Copy(tm); +    } +    Printf(w->code, "if (!%s) {\n", Swig_cresult_name()); +    Append(w->code, "  PyObject *error = PyErr_Occurred();\n"); +    if ((tm) && Len(tm) && (Strcmp(tm, "1") != 0)) { +      Replaceall(tm, "$error", "error"); +      Printv(w->code, Str(tm), "\n", NIL); +    } else { +      Append(w->code, "  if (error) {\n"); +      Printf(w->code, "    Swig::DirectorMethodException::raise(\"Error detected when calling '%s.%s'\");\n", classname, pyname); +      Append(w->code, "  }\n"); +    } +    Append(w->code, "}\n"); +    Delete(tm); + +    /* +     * Python method may return a simple object, or a tuple. +     * for in/out arguments, we have to extract the appropriate PyObjects from the tuple, +     * then marshal everything back to C/C++ (return value and output arguments). +     * +     */ + +    /* marshal return value and other outputs (if any) from PyObject to C/C++ type */ + +    String *cleanup = NewString(""); +    String *outarg = NewString(""); + +    if (outputs > 1) { +      Wrapper_add_local(w, "output", "PyObject *output"); +      Printf(w->code, "if (!PyTuple_Check(%s)) {\n", Swig_cresult_name()); +      Printf(w->code, "  Swig::DirectorTypeMismatchException::raise(\"Python method %s.%sfailed to return a tuple.\");\n", classname, pyname); +      Append(w->code, "}\n"); +    } + +    idx = 0; + +    /* marshal return value */ +    if (!is_void) { +      tm = Swig_typemap_lookup("directorout", n, Swig_cresult_name(), w); +      if (tm != 0) { +	if (outputs > 1) { +	  Printf(w->code, "output = PyTuple_GetItem(%s, %d);\n", Swig_cresult_name(), idx++); +	  Replaceall(tm, "$input", "output"); +	} else { +	  Replaceall(tm, "$input", Swig_cresult_name()); +	} +	char temp[24]; +	sprintf(temp, "%d", idx); +	Replaceall(tm, "$argnum", temp); + +	/* TODO check this */ +	if (Getattr(n, "wrap:disown")) { +	  Replaceall(tm, "$disown", "SWIG_POINTER_DISOWN"); +	} else { +	  Replaceall(tm, "$disown", "0"); +	} +	if (Getattr(n, "tmap:directorout:implicitconv")) { +	  Replaceall(tm, "$implicitconv", get_implicitconv_flag(n)); +	} +	Replaceall(tm, "$result", "c_result"); +	Printv(w->code, tm, "\n", NIL); +	Delete(tm); +      } else { +	Swig_warning(WARN_TYPEMAP_DIRECTOROUT_UNDEF, input_file, line_number, +		     "Unable to use return type %s in director method %s::%s (skipping method).\n", SwigType_str(returntype, 0), SwigType_namestr(c_classname), +		     SwigType_namestr(name)); +	status = SWIG_ERROR; +      } +    } + +    /* marshal outputs */ +    for (p = l; p;) { +      if ((tm = Getattr(p, "tmap:directorargout")) != 0) { +	if (outputs > 1) { +	  Printf(w->code, "output = PyTuple_GetItem(%s, %d);\n", Swig_cresult_name(), idx++); +	  Replaceall(tm, "$result", "output"); +	} else { +	  Replaceall(tm, "$result", Swig_cresult_name()); +	} +	Replaceall(tm, "$input", Getattr(p, "emit:directorinput")); +	Printv(w->code, tm, "\n", NIL); +	p = Getattr(p, "tmap:directorargout:next"); +      } else { +	p = nextSibling(p); +      } +    } + +    /* any existing helper functions to handle this? */ +    if (allow_thread) { +      Append(w->code, "}\n"); +      thread_end_block(n, w->code); +    } + +    Delete(parse_args); +    Delete(arglist); +    Delete(cleanup); +    Delete(outarg); +  } + +  if (!is_void) { +    if (!(ignored_method && !pure_virtual)) { +      String *rettype = SwigType_str(returntype, 0); +      if (!SwigType_isreference(returntype)) { +	Printf(w->code, "return (%s) c_result;\n", rettype); +      } else { +	Printf(w->code, "return (%s) *c_result;\n", rettype); +      } +      Delete(rettype); +    } +  } + +  Append(w->code, "}\n"); + +  // We expose protected methods via an extra public inline method which makes a straight call to the wrapped class' method +  String *inline_extra_method = NewString(""); +  if (dirprot_mode() && !is_public(n) && !pure_virtual) { +    Printv(inline_extra_method, declaration, NIL); +    String *extra_method_name = NewStringf("%sSwigPublic", name); +    Replaceall(inline_extra_method, name, extra_method_name); +    Replaceall(inline_extra_method, ";\n", " {\n      "); +    if (!is_void) +      Printf(inline_extra_method, "return "); +    String *methodcall = Swig_method_call(super, l); +    Printv(inline_extra_method, methodcall, ";\n    }\n", NIL); +    Delete(methodcall); +    Delete(extra_method_name); +  } + +  /* emit the director method */ +  if (status == SWIG_OK) { +    if (!Getattr(n, "defaultargs")) { +      Replaceall(w->code, "$symname", symname); +      Wrapper_print(w, f_directors); +      Printv(f_directors_h, declaration, NIL); +      Printv(f_directors_h, inline_extra_method, NIL); +    } +  } + +  /* clean up */ +  Delete(wrap_args); +  Delete(pclassname); +  DelWrapper(w); +  return status; +} + +/* ----------------------------------------------------------------------------- + * swig_python()    - Instantiate module + * ----------------------------------------------------------------------------- */ + +static Language *new_swig_python() { +  return new PYTHON(); +} +extern "C" Language *swig_python(void) { +  return new_swig_python(); +} diff --git a/contrib/tools/swig/Source/Modules/r.cxx b/contrib/tools/swig/Source/Modules/r.cxx new file mode 100644 index 00000000000..9b465a5716e --- /dev/null +++ b/contrib/tools/swig/Source/Modules/r.cxx @@ -0,0 +1,2889 @@ + +/* ----------------------------------------------------------------------------- + * This file is part of SWIG, which is licensed as a whole under version 3 + * (or any later version) of the GNU General Public License. Some additional + * terms also apply to certain portions of SWIG. The full details of the SWIG + * license and copyrights can be found in the LICENSE and COPYRIGHT files + * included with the SWIG source code as distributed by the SWIG developers + * and at https://www.swig.org/legal.html. + * + * r.cxx + * + * R language module for SWIG. + * ----------------------------------------------------------------------------- */ + +#include "swigmod.h" +#include "cparse.h" + +static String* replaceInitialDash(const String *name) +{ +  String *retval; +  if (!Strncmp(name, "_", 1)) { +    retval = Copy(name); +    Insert(retval, 0, "s"); +  } else { +    retval = Copy(name); +  } +  return retval; +} + +static String * getRTypeName(SwigType *t, int *outCount = NULL) { +  String *b = SwigType_base(t); +  List *els = SwigType_split(t); +  int count = 0; +  int i; + +  if(Strncmp(b, "struct ", 7) == 0) +    Replace(b, "struct ", "", DOH_REPLACE_FIRST); + +  for(i = 0; i < Len(els); i++) { +    String *el = Getitem(els, i); +    if(Strcmp(el, "p.") == 0 || Strncmp(el, "a(", 2) == 0) { +      count++; +      Append(b, "Ref"); +    } +  } +  if(outCount) +    *outCount = count; + +  String *tmp = NewString(""); +  char *retName = Char(SwigType_manglestr(t)); +  Insert(tmp, 0, retName); +  return tmp; + +} + +/* -------------------------------------------------------------- + * Tries to get the resolved name, with options of adding + * or removing a layer of references. Take care not + * to request both + * --------------------------------------------------------------*/ + +static String *getRClassName(String *retType, int deRef=0, int upRef=0) { +  SwigType *resolved = SwigType_typedef_resolve_all(retType); +  int ispointer = SwigType_ispointer(resolved); +  int isreference = SwigType_isreference(resolved); +  if (upRef) { +    SwigType_add_pointer(resolved); +  } +  if (deRef) { +    if (ispointer) { +      SwigType_del_pointer(resolved); +    } +    if (isreference) { +      SwigType_del_reference(resolved); +    } +  }  +  String *tmp = NewString(""); +  Insert(tmp, 0, Char(SwigType_manglestr(resolved))); +  return(tmp); +} + +/* -------------------------------------------------------------- + * Tries to get the name of the R class corresponding  to the given type + * e.g. struct A * is ARef,  struct A**  is  ARefRef. + * Now handles arrays, i.e. struct A[2] + * --------------------------------------------------------------*/ + + +static String * getRClassNameCopyStruct(String *retType, int addRef) { +  String *tmp = NewString(""); + +  List *l = SwigType_split(retType); +  int n = Len(l); +  if(!l || n == 0) { +#ifdef R_SWIG_VERBOSE +    Printf(stdout, "SwigType_split return an empty list for %s\n", retType); +#endif +    return(tmp); +  } + + +  String *el = Getitem(l, n-1); +  char *ptr = Char(el); +  if(strncmp(ptr, "struct ", 7) == 0) +    ptr += 7; + +  Printf(tmp, "%s", ptr); + +  if(addRef) { +    for(int i = 0; i < n; i++) { +      if(Strcmp(Getitem(l, i), "p.") == 0 || +	 Strncmp(Getitem(l, i), "a(", 2) == 0) +	Printf(tmp, "Ref"); +    } +  } + +  return tmp; +} + + +/* ------------------------------------------------------------- + * Write the elements of a list to the File*, one element per line. + * If quote  is true, surround the element with "element". + * This takes care of inserting a tab in front of each line and also + * a comma after each element, except the last one. + * --------------------------------------------------------------*/ + + +static void writeListByLine(List *l, File *out, bool quote = 0) { +  int i, n = Len(l); +  for(i = 0; i < n; i++) +    Printf(out, "%s%s%s%s%s\n", tab8, +	   quote ? "\"" :"", +	   Getitem(l, i), +	   quote ? "\"" :"", i < n-1 ? "," : ""); +} + + +static const char *usage = "\ +R Options (available with -r)\n\ +     -copystruct      - Emit R code to copy C structs (on by default)\n\ +     -debug           - Output debug\n\ +     -dll <name>      - Name of the DLL (without the .dll or .so suffix).\n\ +	                Default is the module name.\n\ +     -gc              - Aggressive garbage collection\n\ +     -memoryprof      - Add memory profile\n\ +     -namespace       - Output NAMESPACE file\n\ +     -no-init-code    - Turn off the generation of the R_init_<pkgname> code\n\ +	                (registration information still generated)\n\ +     -package <name>  - Package name for the PACKAGE argument of the R .Call()\n\ +	                invocations. Default is the module name.\n\ +"; + + + +/* ------------------------------------------------------------- + * Display the help for this module on the screen/console. + * --------------------------------------------------------------*/ + +static void showUsage() { +  fputs(usage, stdout); +} + +static bool expandTypedef(SwigType *t) { +  if (SwigType_isenum(t)) return false; +  String *prefix = SwigType_prefix(t); +  if (Strncmp(prefix, "f", 1)) return false; +  if (Strncmp(prefix, "p.f", 3)) return false; +  return true; +} + + +/* ------------------------------------------------------------- + * Determine whether  we should add a .copy argument to the S function + * that wraps/interfaces to the routine that returns the given type. + * --------------------------------------------------------------*/ + +static int addCopyParameter(SwigType *type) { +  int ok = 0; +  ok = Strncmp(type, "struct ", 7) == 0 || Strncmp(type, "p.struct ", 9) == 0; +  if(!ok) { +    ok = Strncmp(type, "p.", 2); +  } + +  return(ok); +} + +static void replaceRClass(String *tm, SwigType *type) { +  String *tmp = getRClassName(type, 0, 0); +  String *tmp_base = getRClassName(type, 1, 0); +  String *tmp_ref = getRClassName(type, 0, 1); +  Replaceall(tm, "$R_class", tmp); +  Replaceall(tm, "$*R_class", tmp_base); +  Replaceall(tm, "$&R_class", tmp_ref); +  Delete(tmp); Delete(tmp_base); Delete(tmp_ref); +} + +class R : public Language { +public: +  R(); +  void registerClass(Node *n); +  void main(int argc, char *argv[]); +  int top(Node *n); + +  void dispatchFunction(Node *n); +  int functionWrapper(Node *n); +  int constantWrapper(Node *n); +  int variableWrapper(Node *n); + +  int classDeclaration(Node *n); +  int enumDeclaration(Node *n); +  String *enumValue(Node *n); +  virtual int enumvalueDeclaration(Node *n); +  int membervariableHandler(Node *n); + +  int typedefHandler(Node *n); + +  static List *Swig_overload_rank(Node *n, bool script_lang_wrapping); + +  int memberfunctionHandler(Node *n) { +    if (debugMode) +      Printf(stdout, "<memberfunctionHandler> %s %s\n", +	     Getattr(n, "name"), +	     Getattr(n, "type")); +    member_name = Getattr(n, "sym:name"); +    processing_class_member_function = 1; +    int status = Language::memberfunctionHandler(n); +    processing_class_member_function = 0; +    return status; +  } + +  /* Grab the name of the current class being processed so that we can +     deal with members of that class. */ +  int classHandler(Node *n){ +    if(!ClassMemberTable) +      ClassMemberTable = NewHash(); + +    class_name = Getattr(n, "name"); +    int status = Language::classHandler(n); + +    class_name = NULL; +    return status; +  } + +  String *runtimeCode(); +  void replaceSpecialVariables(String *method, String *tm, Parm *parm); + +protected: +  int addRegistrationRoutine(String *rname, int nargs); +  int outputRegistrationRoutines(File *out); + +  int outputCommandLineArguments(File *out); +  int generateCopyRoutines(Node *n); +  int DumpCode(Node *n); + +  int OutputMemberReferenceMethod(String *className, int isSet, List *memberList, List *nameList, List *typeList, File *out); +  int defineArrayAccessors(SwigType *type); + +  void addNamespaceFunction(String *name) { +    if(!namespaceFunctions) +      namespaceFunctions = NewList(); +    Append(namespaceFunctions, name); +  } + +  void addNamespaceMethod(String *name) { +    if(!namespaceMethods) +      namespaceMethods = NewList(); +    Append(namespaceMethods, name); +  } + +  String* processType(SwigType *t, Node *n, int *nargs = NULL); +  String *createFunctionPointerHandler(SwigType *t, Node *n, int *nargs); +  int addFunctionPointerProxy(String *name, Node *n, SwigType *t, String *s_paramTypes) { +    /*XXX Do we need to put the t in there to get the return type later. */ +    if(!functionPointerProxyTable) +      functionPointerProxyTable = NewHash(); + +    Setattr(functionPointerProxyTable, name, n); + +    Setattr(SClassDefs, name, name); +    Printv(s_classes, "setClass('", +	   name, +	   "',\n", tab8, +	   "prototype = list(parameterTypes = c(", s_paramTypes, "),\n", +	   tab8, tab8, tab8, +	   "returnType = '", SwigType_manglestr(t), "'),\n", tab8, +	   "contains = 'CRoutinePointer')\n\n##\n", NIL); + +    return SWIG_OK; +  } + + +  void addSMethodInfo(String *name, +		      String *argType, int nargs); +  // Simple initialization such as constant strings that can be reused. +  void init(); + + +  void addAccessor(String *memberName, Wrapper *f, +		   String *name, String *methodSetGet); + +  static int getFunctionPointerNumArgs(Node *n, SwigType *tt); + +  // filtering of class member lists by function type. Used in constructing accessors +  // are we allowed to use stl style functors to customise this? +  List* filterMemberList(List *class_member_function_types, List *class_member_other, String *R_MEMBER, bool equal); + +protected: +  bool copyStruct; +  bool memoryProfile; +  bool aggressiveGc; + +  // Strings into which we cumulate the generated code that is to be written +  //vto the files. +  String *enum_values; +  String *enum_def_calls; +  String *sfile; +  String *f_init; +  String *s_classes; +  String *f_begin; +  String *f_runtime; +  String *f_wrapper; +  String *s_header; +  String *f_wrappers; +  String *s_init; +  String *s_init_routine; +  String *s_namespace; + +  // State variables that carry information across calls to functionWrapper() +  // from  member accessors and class declarations. +  String *opaqueClassDeclaration; +  int processing_variable; +  int processing_member_access_function; +  String *member_name; +  String *class_name; + +  String *R_MEMBER_NORMAL; +  String *R_MEMBER_SET; +  String *R_MEMBER_GET; + +  int processing_class_member_function; +  // Spread out the lists so that they are simpler to process +  // by storing the type of the method (i.e. set, get or nothing) +  // and having separate lists for name, membername and wrapper +  List *class_member_function_types; +  List *class_member_function_names; +  List *class_member_function_membernames; +  List *class_member_function_wrappernames; +  /* */ +  Hash *ClassMemberTable; +  Hash *ClassMethodsTable; +  Hash *SClassDefs; +  Hash *SMethodInfo; + +  // Information about routines that are generated and to be registered with +  // R for dynamic lookup. +  Hash *registrationTable; +  Hash *functionPointerProxyTable; + +  List *namespaceFunctions; +  List *namespaceMethods; +  List *namespaceClasses; // Probably can do this from ClassMemberTable. + + +  // Store a copy of the command line. +  // Need only keep a string that has it formatted. +  char **Argv; +  int    Argc; +  bool inCPlusMode; + +  // State variables that we remember from the command line settings +  // potentially that govern the code we generate. +  String *DllName; +  String *Rpackage; +  bool    noInitializationCode; +  bool    outputNamespaceInfo; + +  String *UnProtectWrapupCode; + +  // Static members +  static bool debugMode; +}; + +R::R() : +  copyStruct(false), +  memoryProfile(false), +  aggressiveGc(false), +  enum_values(0), +  enum_def_calls(0), +  sfile(0), +  f_init(0), +  s_classes(0), +  f_begin(0), +  f_runtime(0), +  f_wrapper(0), +  s_header(0), +  f_wrappers(0), +  s_init(0), +  s_init_routine(0), +  s_namespace(0), +  opaqueClassDeclaration(0), +  processing_variable(0), +  processing_member_access_function(0), +  member_name(0), +  class_name(0), +  R_MEMBER_NORMAL(NewString("normal")), +  R_MEMBER_SET(NewString("set")), +  R_MEMBER_GET(NewString("get")), +  processing_class_member_function(0), +  class_member_function_types(0), +  class_member_function_names(0), +  class_member_function_membernames(0), +  class_member_function_wrappernames(0), +  ClassMemberTable(0), +  ClassMethodsTable(0), +  SClassDefs(0), +  SMethodInfo(0), +  registrationTable(0), +  functionPointerProxyTable(0), +  namespaceFunctions(0), +  namespaceMethods(0), +  namespaceClasses(0), +  Argv(0), +  Argc(0), +  inCPlusMode(false), +  DllName(0), +  Rpackage(0), +  noInitializationCode(false), +  outputNamespaceInfo(false), +  UnProtectWrapupCode(0) { +} + +bool R::debugMode = false; + +int R::getFunctionPointerNumArgs(Node *n, SwigType *tt) { +  (void) tt; +  n = Getattr(n, "type"); +  if (debugMode) +    Printf(stdout, "type: %s\n", n); + +  ParmList *parms = Getattr(n, "parms"); +  if (debugMode) +    Printf(stdout, "parms = %p\n", parms); +  return ParmList_len(parms); +} + + +void R::addSMethodInfo(String *name, String *argType, int nargs) { +  (void) argType; + +  if(!SMethodInfo) +    SMethodInfo = NewHash(); +  if (debugMode) +    Printf(stdout, "[addMethodInfo] %s\n", name); + +  Hash *tb = Getattr(SMethodInfo, name); + +  if(!tb) { +    tb = NewHash(); +    Setattr(SMethodInfo, name, tb); +  } + +  String *str = Getattr(tb, "max"); +  int max = -1; +  if(str) +    max = atoi(Char(str)); +  if(max < nargs) { +    if(str)  Delete(str); +    str = NewStringf("%d", max); +    Setattr(tb, "max", str); +  } +} + +/* ---------------------------------------- + * Returns the name of the new routine. + * ------------------------------------------ */ + +String * R::createFunctionPointerHandler(SwigType *t, Node *n, int *numArgs) { +  String *funName = SwigType_manglestr(t); + +  /* See if we have already processed this one. */ +  if(functionPointerProxyTable && Getattr(functionPointerProxyTable, funName)) +    return funName; + +  if (debugMode) +    Printf(stdout, "<createFunctionPointerHandler> Defining %s\n",  t); + +  SwigType *rettype = Copy(Getattr(n, "type")); +  SwigType *funcparams = SwigType_functionpointer_decompose(rettype); +  String *rtype = SwigType_str(rettype, 0); + +  // ParmList *parms = Getattr(n, "parms"); +  // memory leak +  ParmList *parms = SwigType_function_parms(SwigType_del_pointer(Copy(t)), n); + + +  if (debugMode) { +    Printf(stdout, "Type: %s\n", t); +    Printf(stdout, "Return type: %s\n", SwigType_base(t)); +  } + +  bool isVoidType = Strcmp(rettype, "void") == 0; +  if (debugMode) +    Printf(stdout, "%s is void ? %s  (%s)\n", funName, isVoidType ? "yes" : "no", rettype); + +  Wrapper *f = NewWrapper(); + +  /* Go through argument list, attach lnames for arguments */ +  int i = 0; +  Parm *p = parms; +  for (i = 0; p; p = nextSibling(p), ++i) { +    String *arg = Getattr(p, "name"); +    String *lname; +    if (!arg && Cmp(Getattr(p, "type"), "void")) { +      lname = NewStringf("arg%d", i+1); +      Setattr(p, "name", lname); +    } else +      lname = arg; + +    Setattr(p, "lname", lname); +  } + +  Swig_typemap_attach_parms("out", parms, f); +  Swig_typemap_attach_parms("scoerceout", parms, f); +  Swig_typemap_attach_parms("scheck", parms, f); + +  Printf(f->def, "%s %s(", rtype, funName); + +  emit_parameter_variables(parms, f); +  emit_return_variable(n, rettype, f); +  //  emit_attach_parmmaps(parms,f); + +  /*  Using weird name and struct to avoid potential conflicts. */ +  Wrapper_add_local(f, "r_swig_cb_data", "RCallbackFunctionData *r_swig_cb_data = R_SWIG_getCallbackFunctionData()"); +  String *lvar = NewString("r_swig_cb_data"); + +  Wrapper_add_local(f, "r_tmp", "SEXP r_tmp"); // for use in converting arguments to R objects for call. +  Wrapper_add_local(f, "r_nprotect", "int r_nprotect = 0"); // for use in converting arguments to R objects for call. +  Wrapper_add_local(f, "r_vmax", "char * r_vmax= 0"); // for use in converting arguments to R objects for call. + +  // Add local for error code in return value.  This is not in emit_return_variable because that assumes an out typemap +  // whereas the type makes are reverse +  Wrapper_add_local(f, "ecode", "int ecode = 0"); + +  p = parms; +  int nargs = ParmList_len(parms); +  if(numArgs) { +    *numArgs = nargs; +    if (debugMode) +      Printf(stdout, "Setting number of parameters to %d\n", *numArgs); +  } +  String *setExprElements = NewString(""); + +  String *s_paramTypes = NewString(""); +  for(i = 0; p; i++) { +    SwigType *tt = Getattr(p, "type"); +    SwigType *name = Getattr(p, "name"); +    SwigType *swig_parm_name = NewStringf("swigarg_%s", name); +    String *tm = Getattr(p, "tmap:out"); +    bool isVoidParm = Strcmp(tt, "void") == 0; +    if (isVoidParm) +      Printf(f->def, "%s", SwigType_str(tt, 0)); +    else +      Printf(f->def, "%s %s", SwigType_str(tt, 0), swig_parm_name); +    if (tm) { +      String *lstr = SwigType_lstr(tt, 0); +      if (SwigType_isreference(tt) || SwigType_isrvalue_reference(tt)) { +	Printf(f->code, "%s = (%s) &%s;\n", Getattr(p, "lname"), lstr, swig_parm_name); +      } else if (!isVoidParm) { +	Printf(f->code, "%s = (%s) %s;\n", Getattr(p, "lname"), lstr, swig_parm_name); +      } +      Replaceall(tm, "$1", name); +      Replaceall(tm, "$result", "r_tmp"); +      if (debugMode) { +        Printf(stdout, "Calling Replace A: %s\n", Getattr(p,"type")); +      } +      replaceRClass(tm, Getattr(p,"type")); +      Replaceall(tm,"$owner", "0"); +      Delete(lstr); +    }  +     +    Printf(setExprElements, "%s\n", tm); +    Printf(setExprElements, "SETCAR(r_swig_cb_data->el, %s);\n", "r_tmp"); +    Printf(setExprElements, "r_swig_cb_data->el = CDR(r_swig_cb_data->el);\n\n"); + +    Printf(s_paramTypes, "'%s'", SwigType_manglestr(tt)); + + +    p = nextSibling(p); +    if(p) { +      Printf(f->def, ", "); +      Printf(s_paramTypes, ", "); +    } +  } + +  Printf(f->def,  ") {\n"); + +  Printf(f->code, "Rf_protect(%s->expr = Rf_allocVector(LANGSXP, %d));\n", lvar, nargs + 1); +  Printf(f->code, "r_nprotect++;\n"); +  Printf(f->code, "r_swig_cb_data->el = r_swig_cb_data->expr;\n\n"); + +  Printf(f->code, "SETCAR(r_swig_cb_data->el, r_swig_cb_data->fun);\n"); +  Printf(f->code, "r_swig_cb_data->el = CDR(r_swig_cb_data->el);\n\n"); + +  Printf(f->code, "%s\n\n", setExprElements); + +  Printv(f->code, "r_swig_cb_data->retValue = R_tryEval(", +	 "r_swig_cb_data->expr,", +	 " R_GlobalEnv,", +	 " &r_swig_cb_data->errorOccurred", +	 ");\n", +	 NIL); + +  Printv(f->code, "\n", +	 "if(r_swig_cb_data->errorOccurred) {\n", +	 "R_SWIG_popCallbackFunctionData(1);\n", +	 "Rf_error(\"error in calling R function as a function pointer (", +	 funName, +	 ")\");\n", +	 "}\n", +	 NIL); + + + +  if(!isVoidType) { +    /* Need to deal with the return type of the function pointer, not the function pointer itself. +       So build a new node that has the relevant pieces. +       XXX  Have to be a little more clever so that we can deal with struct A * - the * is getting lost. +       Is this still true? If so, will a SwigType_push() solve things? +    */ +    Parm *bbase = NewParmNode(rettype, n); +    String *returnTM = Swig_typemap_lookup("in", bbase, Swig_cresult_name(), f); +    if(returnTM) { +      String *tm = returnTM; +      Replaceall(tm,"$input", "r_swig_cb_data->retValue"); +      replaceRClass(tm, rettype); +      Replaceall(tm,"$owner", "0"); +      Replaceall(tm,"$disown","0"); +      Printf(f->code, "%s\n", tm); +    } +    Delete(bbase); +  } + +  Printv(f->code, "R_SWIG_popCallbackFunctionData(1);\n", NIL); +  Printv(f->code, "\n", UnProtectWrapupCode, NIL); + +  if (SwigType_isreference(rettype)) { +    Printv(f->code,  "return *", Swig_cresult_name(), ";\n", NIL); +  } else if (SwigType_isrvalue_reference(rettype)) { +    Printv(f->code,  "return std::move(*", Swig_cresult_name(), ");\n", NIL); +  } else if (!isVoidType) { +    Printv(f->code,  "return ", Swig_cresult_name(), ";\n", NIL); +  } + +  Printv(f->code, "\n}\n", NIL); +  Replaceall(f->code, "SWIG_exception_fail", "SWIG_exception_noreturn"); + +  /* To coerce correctly in S, we really want to have an extra/intermediate +     function that handles the scoerceout. +     We need to check if any of the argument types have an entry in +     that map. If none do, the ignore and call the function straight. +     Otherwise, generate a marshalling function. +     Need to be able to find it in S. Or use an entirely generic one +     that evaluates the expressions. +     Handle errors in the evaluation of the function by restoring +     the stack, if there is one in use for this function (i.e. no +     userData). +  */ + +  Wrapper_print(f, f_wrapper); + +  addFunctionPointerProxy(funName, n, t, s_paramTypes); +  Delete(s_paramTypes); +  Delete(rtype); +  Delete(rettype); +  Delete(funcparams); +  DelWrapper(f); + +  return funName; +} + +void R::init() { +  UnProtectWrapupCode = +    NewStringf("%s", "vmaxset(r_vmax);\nif(r_nprotect)  Rf_unprotect(r_nprotect);\n\n"); + +  SClassDefs = NewHash(); + +  sfile = NewString(""); +  f_init = NewString(""); +  s_header = NewString(""); +  f_begin = NewString(""); +  f_runtime = NewString(""); +  f_wrapper = NewString(""); +  s_classes = NewString(""); +  s_init = NewString(""); +  s_init_routine = NewString(""); +  enum_def_calls = NewString(""); +} + + +/* ------------------------------------------------------------- + *  Method from Language that is called to start the entire + *  processing off, i.e. the generation of the code. + *  It is called after the input has been read and parsed. + *  Here we open the output streams and generate the code. + * ------------------------------------------------------------- */ +int R::top(Node *n) { +  String *module = Getattr(n, "name"); + +  if (debugMode) { +    Printf(stdout, "<Top> %s\n", module); +  } + +  if(!Rpackage) +    Rpackage = Copy(module); +  if(!DllName) +    DllName = Copy(module); + +  if(outputNamespaceInfo) { +    s_namespace = NewString(""); +    Swig_register_filebyname("snamespace", s_namespace); +    Printf(s_namespace, "useDynLib(%s)\n", DllName); +  } +  // Register the naming functions +  Swig_name_register("wrapper", "R_swig_%f"); + +  /* Associate the different streams with names so that they can be used in %insert directives by the +     typemap code. */ +  Swig_register_filebyname("sinit", s_init); +  Swig_register_filebyname("sinitroutine", s_init_routine); + +  Swig_register_filebyname("begin", f_begin); +  Swig_register_filebyname("runtime", f_runtime); +  Swig_register_filebyname("init", f_init); +  Swig_register_filebyname("header", s_header); +  Swig_register_filebyname("wrapper", f_wrapper); +  Swig_register_filebyname("s", sfile); +  Swig_register_filebyname("sclasses", s_classes); + +  Swig_banner(f_begin); + +  Swig_obligatory_macros(f_runtime, "R"); + +  Swig_banner_target_lang(s_init, "#"); +  outputCommandLineArguments(s_init); + +  Printf(f_wrapper, "#ifdef __cplusplus\n"); +  Printf(f_wrapper, "extern \"C\" {\n"); +  Printf(f_wrapper, "#endif\n\n"); + +  Language::top(n); + +  Printf(f_wrapper, "#ifdef __cplusplus\n"); +  Printf(f_wrapper, "}\n"); +  Printf(f_wrapper, "#endif\n"); + +  String *type_table = NewString(""); +  SwigType_emit_type_table(f_runtime,f_wrapper); +  Delete(type_table); + +  if(ClassMemberTable) { +    //XXX OutputClassAccessInfo(ClassMemberTable, sfile); +    Delete(ClassMemberTable); +    ClassMemberTable = NULL; +  } + +  Printf(f_init,"}\n"); +  if(registrationTable) +    outputRegistrationRoutines(f_init); + +  /* Now arrange to write the 2 files - .S and .c. */ + +  DumpCode(n); + +  Delete(sfile); +  Delete(s_classes); +  Delete(s_init); +  Delete(f_wrapper); +  Delete(f_init); + +  Delete(s_header); +  Delete(f_runtime); +  Delete(f_begin); + +  return SWIG_OK; +} + + +/* ------------------------------------------------------------- + * Write the generated code  to the .S and the .c files. + * ------------------------------------------------------------- */ +int R::DumpCode(Node *n) { +  String *output_filename = NewString(""); + + +  /* The name of the file in which we will generate the S code. */ +  Printf(output_filename, "%s%s.R", SWIG_output_directory(), Rpackage); + +#ifdef R_SWIG_VERBOSE +  Printf(stdout, "Writing S code to %s\n", output_filename); +#endif + +  File *scode = NewFile(output_filename, "w", SWIG_output_files()); +  if (!scode) { +    FileErrorDisplay(output_filename); +    Exit(EXIT_FAILURE); +  } +  Delete(output_filename); + + +  Printf(scode, "%s\n\n", s_init); +  Printf(scode, "%s\n\n", s_classes); +  Printf(scode, "%s\n", sfile); +  Printf(scode, "%s\n", enum_def_calls); + +  Delete(scode); +  String *outfile = Getattr(n,"outfile"); +  File *runtime = NewFile(outfile,"w", SWIG_output_files()); +  if (!runtime) { +    FileErrorDisplay(outfile); +    Exit(EXIT_FAILURE); +  } + +  Printf(runtime, "%s", f_begin); +  Printf(runtime, "%s\n", f_runtime); +  Printf(runtime, "%s\n", s_header); +  Printf(runtime, "%s\n", f_wrapper); +  Printf(runtime, "%s\n", f_init); + +  Delete(runtime); + +  if(outputNamespaceInfo) { +    output_filename = NewString(""); +    Printf(output_filename, "%sNAMESPACE", SWIG_output_directory()); +    File *ns = NewFile(output_filename, "w", SWIG_output_files()); +    if (!ns) { +      FileErrorDisplay(output_filename); +      Exit(EXIT_FAILURE); +    } +    Delete(output_filename); + +    Printf(ns, "%s\n", s_namespace); + +    Printf(ns, "\nexport(\n"); +    writeListByLine(namespaceFunctions, ns); +    Printf(ns, ")\n"); +    Printf(ns, "\nexportMethods(\n"); +    writeListByLine(namespaceMethods, ns, 1); +    Printf(ns, ")\n"); +    Delete(ns); +    Delete(s_namespace); +  } + +  return SWIG_OK; +} + + +List *R::filterMemberList(List *class_member_types,  +                          List *class_member_other,  +                          String *R_MEMBER, bool equal) { +  // filters class_member_other based on whether corresponding elements of +  // class_member_function_types are equal or notequal to R_MEMBER +  List *CM = NewList(); +  Iterator ftype, other; + +  for (ftype = First(class_member_types), other = First(class_member_other); +       ftype.item;  +       ftype=Next(ftype), other=Next(other)) { +    // verbose, clean up later if the overall structure works +    if (equal) { +      if (ftype.item == R_MEMBER) { +        Append(CM, other.item); +      } +    } else { +      if (ftype.item != R_MEMBER) { +        Append(CM, other.item); +      } +    } +  } +  return(CM); +} + +# if 0 +// not called +/* ------------------------------------------------------------- + * We may need to do more.... so this is left as a + * stub for the moment. + * -------------------------------------------------------------*/ +int R::OutputClassAccessInfo(Hash *tb, File *out) { +  int n = OutputClassMemberTable(tb, out); +  OutputClassMethodsTable(out); +  return n; +} + +/* ------------------------------------------------------------- + * Currently this just writes the information collected about the + * different methods of the C++ classes that have been processed + * to the console. + * This will be used later to define S4 generics and methods. + * --------------------------------------------------------------*/ + +int R::OutputClassMethodsTable(File *) { +  Hash *tb = ClassMethodsTable; + +  if(!tb) +    return SWIG_OK; + +  List *keys = Keys(tb); +  String *key; +  int i, n = Len(keys); +  if (debugMode) { +    for(i = 0; i < n ; i++ ) { +      key = Getitem(keys, i); +      Printf(stdout, "%d) %s\n", i, key); +      List *els = Getattr(tb, key); +      int nels = Len(els); +      Printf(stdout, "\t"); +      for(int j = 0; j < nels; j+=2) { +	Printf(stdout, "%s%s", Getitem(els, j), j < nels - 1 ? ", " : ""); +	Printf(stdout, "%s\n", Getitem(els, j+1)); +      } +      Printf(stdout, "\n"); +    } +  } + +  return SWIG_OK; +} + + +/* -------------------------------------------------------------- + * Iterate over the <class name>_set and <>_get + * elements and generate the $ and $<- functions + * that provide constrained access to the member + * fields in these elements. + + * tb - a hash table that is built up in functionWrapper + * as we process each membervalueHandler. + * The entries are indexed by <class name>_set and + * <class_name>_get. Each entry is a List *. + + * out - the stream where the code is to be written. This is the S + * code stream as we generate only S code here. + * --------------------------------------------------------------*/ + +int R::OutputClassMemberTable(Hash *tb, File *out) { +  List *keys = Keys(tb), *el; + +  String *key; +  int i, n = Len(keys); +  /* Loop over all the  <Class>_set and <Class>_get entries in the table. */ +  /* This function checks for names ending in _set - perhaps it should */ +  /* use attributes of some other form, as it potentially clashes with */ +  /* methods ending in _set */ + +  if(n && outputNamespaceInfo) { +    Printf(s_namespace, "exportClasses("); +  } +  for(i = 0; i < n; i++) { +    key = Getitem(keys, i); +    el = Getattr(tb, key); + +    String *className = Getitem(el, 0); +    char *ptr = Char(key); +    int klen = Len(key); +    int isSet = 0; +    if (klen > 4) { +      ptr = &ptr[klen - 4]; +      isSet = strcmp(ptr, "_set") == 0; +    } + +    if(outputNamespaceInfo) +      Printf(s_namespace, "\"%s\"%s", className, i < n-1 ? "," : ""); +  } +  if(n && outputNamespaceInfo) { +    Printf(s_namespace, ")\n"); +  } + +  return n; +} + +// end not used +#endif +/* -------------------------------------------------------------- + * Write the methods for $ or $<- for accessing a member field in an + * struct or union (or class). + * className - the name of the struct or union (e.g. Bar for struct Bar) + * isSet - a logical value indicating whether the method is for + *	   modifying ($<-) or accessing ($) the member field. + * el - a list of length  2 * # accessible member elements  + 1. + *     The first element is the name of the class. + *     The other pairs are  member name and the name of the R function to access it. + * out - the stream where we write the code. + * --------------------------------------------------------------*/ + +int R::OutputMemberReferenceMethod(String *className, int isSet,   +				   List *memberList, List *nameList, +				   List *typeList, File *out) { +  int numMems = Len(memberList), j; +  int varaccessor = 0; +  if (numMems == 0) +    return SWIG_OK; + +  Wrapper *f = NewWrapper(), *attr = NewWrapper(); + +  Printf(f->def, "function(x, name%s)", isSet ? ", value" : ""); +  Printf(attr->def, "function(x, i, j, ...%s)", isSet ? ", value" : ""); + +  Printf(f->code, "{\n"); +  Printf(f->code, "%saccessorFuns = list(", tab8); + +  Node *itemList = NewHash(); +  bool has_prev = false; +  for(j = 0; j < numMems; j++) { +    String *item = Getitem(memberList, j); +    String *dup = Getitem(nameList, j); +    String *setgetmethod = Getitem(typeList, j); + +    if (setgetmethod == R_MEMBER_GET) +      varaccessor++; + +    if (Getattr(itemList, item)) +      continue; +    Setattr(itemList, item, "1"); + +    String *pitem; +    if (!Strcmp(item, "operator ()")) { +      pitem = NewString("call"); +    } else if (!Strcmp(item, "operator ->")) { +      pitem = NewString("deref"); +    } else if (!Strcmp(item, "operator +")) { +      pitem = NewString("add"); +    } else if (!Strcmp(item, "operator -")) { +      pitem = NewString("sub"); +    } else { +      pitem = Copy(item); +    } +    if (has_prev) +      Printf(f->code, ", "); +    Printf(f->code, "'%s' = %s", pitem, dup); +    has_prev = true; +    Delete(pitem); +  } +  Delete(itemList); +  Printf(f->code, ");\n"); + +  if (!isSet && varaccessor > 0) { +    Printf(f->code, "%svaccessors = c(", tab8); +    bool first = true; +    for(j = 0; j < numMems; j++) { +      String *item = Getitem(memberList, j); +      String *setgetmethod = Getitem(typeList, j); + +      // Check the type here instead of the name +      if (setgetmethod == R_MEMBER_GET) { +	Printf(f->code, "%s'%s'", first ? "" : ", ", item); +	first = false; +      } +    } +    Printf(f->code, ");\n"); +  } + +  Printv(f->code, ";", tab8, +	 "idx = pmatch(name, names(accessorFuns));\n", +	 tab8, +	 "if(is.na(idx)) \n", +	 tab8, tab4, NIL); +  Printf(f->code, "return(callNextMethod(x, name%s));\n", +	 isSet ? ", value" : ""); +  Printv(f->code, tab8, "f = accessorFuns[[idx]];\n", NIL); +  if(isSet) { +    Printv(f->code, tab8, "f(x, value);\n", NIL); +    Printv(f->code, tab8, "x;\n", NIL); // make certain to return the S value. +  } else { +    if (varaccessor) { +      Printv(f->code, tab8, +	     "if (is.na(match(name, vaccessors))) function(...){f(x, ...)} else f(x);\n", NIL); +    } else { +      Printv(f->code, tab8, "function(...){f(x, ...)};\n", NIL); +    } +  } +  Printf(f->code, "}\n"); + +  String *classname_str = SwigType_namestr(className); +  Printf(out, "# Start of accessor method for %s\n", classname_str); +  Printf(out, "setMethod('$%s', '_p%s', ", +	 isSet ? "<-" : "", +	 getRClassName(className)); +  Wrapper_print(f, out); +  Printf(out, ");\n"); + +  if(isSet) { +    Printf(out, "setMethod('[[<-', c('_p%s', 'character'),", +	   getRClassName(className)); +    Insert(f->code, 2, "name = i;\n"); +    Printf(attr->code, "%s", f->code); +    Wrapper_print(attr, out); +    Printf(out, ");\n"); +  } + +  Printf(out, "# end of accessor method for %s\n", classname_str); + +  Delete(classname_str); +  DelWrapper(attr); +  DelWrapper(f); + +  return SWIG_OK; +} + +/* ------------------------------------------------------------- + * Called when a enumeration is to be processed. + * We want to call the R function defineEnumeration(). + * tdname is the typedef of the enumeration, i.e. giving its name. + * --------------------------------------------------------------*/ + +int R::enumDeclaration(Node *n) { +  if (!ImportMode) { +    if (getCurrentClass() && (cplus_mode != PUBLIC)) +      return SWIG_NOWRAP; + +    String *symname = Getattr(n, "sym:name"); + +    // TODO - deal with anonymous enumerations +    // Previous enum code for R didn't wrap them +    if (!symname || Getattr(n, "unnamedinstance")) +      return SWIG_NOWRAP; + +    // create mangled name for the enum +    // This will have content if the %nspace feature is set on +    // the input file +    String *nspace = Getattr(n, "sym:nspace"); // NSpace/getNSpace() only works during Language::enumDeclaration call +    String *ename; + +    String *name = Getattr(n, "name"); +    ename = getRClassName(name);  +    if (debugMode) { +      Node *current_class = getCurrentClass(); +      String *cl = NewString(""); +      if (current_class) { +        cl = getEnumClassPrefix(); +      } +      Printf(stdout, "enumDeclaration: %s, %s, %s, %s, %s\n", name, symname, nspace, ename, cl); +    } +    Delete(name); +    // set up a call to create the R enum structure. The list of +    // individual elements will be built in enum_code +    enum_values = 0; +    // Emit each enum item +    Language::enumDeclaration(n); +       +    Printf(enum_def_calls, "defineEnumeration(\"%s\",\n .values=c(%s))\n\n", ename, enum_values); +    Delete(enum_values); +    Delete(ename); +  } +  return SWIG_OK; +} + +/* ------------------------------------------------------------- +* --------------------------------------------------------------*/ + +int R::enumvalueDeclaration(Node *n) { +  if (getCurrentClass() && (cplus_mode != PUBLIC)) { +    Printf(stdout, "evd: Not public\n"); +    return SWIG_NOWRAP; +  } + +  Swig_require("enumvalueDeclaration", n, "*name", "?value", NIL); +  String *symname = Getattr(n, "sym:name"); +  String *value = Getattr(n, "value"); +  String *name = Getattr(n, "name"); +  Node *parent = parentNode(n); +  String *parent_name = Getattr(parent, "name"); +  String *newsymname = 0; +  String *tmpValue; + +  // Strange hack from parent method +  if (value) +    tmpValue = NewString(value); +  else +    tmpValue = NewString(name); +  // Note that this is used in enumValue() amongst other places +  Setattr(n, "value", tmpValue); +   +  // Deal with enum values that are not int +  int swigtype = SwigType_type(Getattr(n, "type")); +  if (swigtype == T_BOOL) { +    const char *val = Equal(Getattr(n, "enumvalue"), "true") ? "1" : "0"; +    Setattr(n, "enumvalue", val); +  } else if (swigtype == T_CHAR) { +    String *val = NewStringf("'%s'", Getattr(n, "enumvalue")); +    Setattr(n, "enumvalue", val); +    Delete(val); +  } + +  if (GetFlag(parent, "scopedenum")) { +    newsymname = Swig_name_member(0, Getattr(parent, "sym:name"), symname); +    symname = newsymname; +  } + +  { +    // Wrap C/C++ enums with constant integers or use the typesafe enum pattern +    SwigType *typemap_lookup_type = parent_name ? parent_name : NewString("enum "); +    if (debugMode) { +      Printf(stdout, "Setting type: %s\n", Copy(typemap_lookup_type)); +    } +    Setattr(n, "type", typemap_lookup_type); +     +    // Simple integer constants +    // Note these are always generated for anonymous enums, no matter what enum_feature is specified +    // Code generated is the same for SimpleEnum and TypeunsafeEnum -> the class it is generated into is determined later + +    String *value = enumValue(n); +    if (enum_values) { +      Printf(enum_values, ",\n\"%s\" = %s", name, value); +    } else { +      enum_values = NewString(""); +      Printf(enum_values, "\"%s\" = %s", name, value); +    } + +    Delete(value); +  } + +  return SWIG_OK; +} + + +/* ------------------------------------------------------------- + * Create accessor functions for variables. + * Does not create equivalent wrappers for enumerations, + * which are handled differently + * --------------------------------------------------------------*/ + +int R::variableWrapper(Node *n) { +  String *name = Getattr(n, "sym:name"); +  if (debugMode) { +    Printf(stdout, "variableWrapper %s\n", n); +  } +  processing_variable = 1; +  Language::variableWrapper(n); // Force the emission of the _set and _get function wrappers. +  processing_variable = 0; + + +  SwigType *ty = Getattr(n, "type"); +  String *nodeType = nodeType(n); +  int addCopyParam = addCopyParameter(ty); + +  //XXX +  processType(ty, n); + +  if (nodeType && !Strcmp(nodeType, "enumitem")) { +    /* special wrapper for enums - don't want the R _set, _get functions*/ +    if (debugMode) { +      Printf(stdout, "variableWrapper enum branch\n"); +    } +  } else if(!SwigType_isconst(ty)) { +    Wrapper *f = NewWrapper(); +    Printf(f->def, "%s = \nfunction(value%s)\n{\n", +	   name, addCopyParam ? ", .copy = FALSE" : ""); +    Printv(f->code, "if(missing(value)) {\n", +	   name, "_get(", addCopyParam ? ".copy" : "", ")\n}", NIL); +    Printv(f->code, " else {\n", +	   name, "_set(value)\n}\n}", NIL); + +    Wrapper_print(f, sfile); +    DelWrapper(f); +  } else { +    Printf(sfile, "%s = %s_get\n", name, name); +  } + +  return SWIG_OK; +} + +/* ------------------------------------------------------------- + * Creates accessor functions for class members. + + * ToDo - this version depends on naming conventions and needs + * to be replaced. + * --------------------------------------------------------------*/ + +void R::addAccessor(String *memberName, Wrapper *wrapper, String *name, +		    String *methodSetGet) { + +  if (!class_member_function_names) { +    class_member_function_names = NewList(); +    class_member_function_membernames = NewList(); +    class_member_function_wrappernames = NewList(); +    class_member_function_types = NewList(); +  } +  Append(class_member_function_types, methodSetGet); +  Append(class_member_function_names, name); +  Append(class_member_function_membernames, memberName); +   +  String *tmp = NewString(""); +  Wrapper_print(wrapper, tmp); +  Append(class_member_function_wrappernames, tmp); +  // if we could put the wrapper in directly:       Append(l, Copy(sfun)); +  if (debugMode) +    Printf(stdout, "Adding accessor: %s (%s) => %s\n", memberName, name, tmp); +} + +#define MAX_OVERLOAD 256 + +namespace { +struct Overloaded { +  Node      *n;          /* Node                               */ +  int        argc;       /* Argument count                     */ +  ParmList  *parms;      /* Parameters used for overload check */ +  int        error;      /* Ambiguity error                    */ +}; +} + +List * R::Swig_overload_rank(Node *n, +	                     bool script_lang_wrapping) { +  Overloaded  nodes[MAX_OVERLOAD]; +  int         nnodes = 0; +  Node *o = Getattr(n,"sym:overloaded"); + + +  if (!o) return 0; + +  Node *c = o; +  while (c) { +    if (Getattr(c,"error")) { +      c = Getattr(c,"sym:nextSibling"); +      continue; +    } +    /* Make a list of all the declarations (methods) that are overloaded with +     * this one particular method name */ + +    if (Getattr(c,"wrap:name")) { +      nodes[nnodes].n = c; +      nodes[nnodes].parms = Getattr(c,"wrap:parms"); +      nodes[nnodes].argc = emit_num_required(nodes[nnodes].parms); +      nodes[nnodes].error = 0; +      nnodes++; +    } +    c = Getattr(c,"sym:nextSibling"); +  } + +  /* Sort the declarations by required argument count */ +  { +    int i,j; +    for (i = 0; i < nnodes; i++) { +      for (j = i+1; j < nnodes; j++) { +	if (nodes[i].argc > nodes[j].argc) { +	  Overloaded t = nodes[i]; +	  nodes[i] = nodes[j]; +	  nodes[j] = t; +	} +      } +    } +  } + +  /* Sort the declarations by argument types */ +  { +    int i,j; +    for (i = 0; i < nnodes-1; i++) { +      if (nodes[i].argc == nodes[i+1].argc) { +	for (j = i+1; (j < nnodes) && (nodes[j].argc == nodes[i].argc); j++) { +	  Parm *p1 = nodes[i].parms; +	  Parm *p2 = nodes[j].parms; +	  int   differ = 0; +	  int   num_checked = 0; +	  while (p1 && p2 && (num_checked < nodes[i].argc)) { +	    if (debugMode) { +	      Printf(stdout,"p1 = '%s', p2 = '%s'\n", Getattr(p1,"type"), Getattr(p2,"type")); +	    } +	    if (checkAttribute(p1,"tmap:in:numinputs","0")) { +	      p1 = Getattr(p1,"tmap:in:next"); +	      continue; +	    } +	    if (checkAttribute(p2,"tmap:in:numinputs","0")) { +	      p2 = Getattr(p2,"tmap:in:next"); +	      continue; +	    } +	    String *t1 = Getattr(p1,"tmap:typecheck:precedence"); +	    String *t2 = Getattr(p2,"tmap:typecheck:precedence"); +	    if (debugMode) { +	      Printf(stdout,"t1 = '%s', t2 = '%s'\n", t1, t2); +	    } +	    if ((!t1) && (!nodes[i].error)) { +	      Swig_warning(WARN_TYPEMAP_TYPECHECK, Getfile(nodes[i].n), Getline(nodes[i].n), +			   "Overloaded method %s not supported (incomplete type checking rule - no precedence level in typecheck typemap for '%s').\n", +			   Swig_name_decl(nodes[i].n), SwigType_str(Getattr(p1, "type"), 0)); +	      nodes[i].error = 1; +	    } else if ((!t2) && (!nodes[j].error)) { +	      Swig_warning(WARN_TYPEMAP_TYPECHECK, Getfile(nodes[j].n), Getline(nodes[j].n), +			   "Overloaded method %s not supported (incomplete type checking rule - no precedence level in typecheck typemap for '%s').\n", +			   Swig_name_decl(nodes[j].n), SwigType_str(Getattr(p2, "type"), 0)); +	      nodes[j].error = 1; +	    } +	    if (t1 && t2) { +	      int t1v, t2v; +	      t1v = atoi(Char(t1)); +	      t2v = atoi(Char(t2)); +	      differ = t1v-t2v; +	    } +	    else if (!t1 && t2) differ = 1; +	    else if (t1 && !t2) differ = -1; +	    else if (!t1 && !t2) differ = -1; +	    num_checked++; +	    if (differ > 0) { +	      Overloaded t = nodes[i]; +	      nodes[i] = nodes[j]; +	      nodes[j] = t; +	      break; +	    } else if ((differ == 0) && (Strcmp(t1,"0") == 0)) { +	      t1 = Getattr(p1,"ltype"); +	      if (!t1) { +		t1 = SwigType_ltype(Getattr(p1,"type")); +		if (Getattr(p1,"tmap:typecheck:SWIGTYPE")) { +		  SwigType_add_pointer(t1); +		} +		Setattr(p1,"ltype",t1); +	      } +	      t2 = Getattr(p2,"ltype"); +	      if (!t2) { +		t2 = SwigType_ltype(Getattr(p2,"type")); +		if (Getattr(p2,"tmap:typecheck:SWIGTYPE")) { +		  SwigType_add_pointer(t2); +		} +		Setattr(p2,"ltype",t2); +	      } + +	      /* Need subtype check here.  If t2 is a subtype of t1, then we need to change the +	         order */ + +	      if (SwigType_issubtype(t2,t1)) { +		Overloaded t = nodes[i]; +		nodes[i] = nodes[j]; +		nodes[j] = t; +	      } + +	      if (Strcmp(t1,t2) != 0) { +		differ = 1; +		break; +	      } +	    } else if (differ) { +	      break; +	    } +	    if (Getattr(p1,"tmap:in:next")) { +	      p1 = Getattr(p1,"tmap:in:next"); +	    } else { +	      p1 = nextSibling(p1); +	    } +	    if (Getattr(p2,"tmap:in:next")) { +	      p2 = Getattr(p2,"tmap:in:next"); +	    } else { +	      p2 = nextSibling(p2); +	    } +	  } +	  if (!differ) { +	    /* See if declarations differ by const only */ +	    String *d1 = Getattr(nodes[i].n, "decl"); +	    String *d2 = Getattr(nodes[j].n, "decl"); +	    if (d1 && d2) { +	      String *dq1 = Copy(d1); +	      String *dq2 = Copy(d2); +	      if (SwigType_isconst(d1)) { +		Delete(SwigType_pop(dq1)); +	      } +	      if (SwigType_isconst(d2)) { +		Delete(SwigType_pop(dq2)); +	      } +	      if (Strcmp(dq1, dq2) == 0) { + +		if (SwigType_isconst(d1) && !SwigType_isconst(d2)) { +		  if (script_lang_wrapping) { +		    // Swap nodes so that the const method gets ignored (shadowed by the non-const method) +		    Overloaded t = nodes[i]; +		    nodes[i] = nodes[j]; +		    nodes[j] = t; +		  } +		  differ = 1; +		  if (!nodes[j].error) { +		    if (script_lang_wrapping) { +		      Swig_warning(WARN_LANG_OVERLOAD_CONST, Getfile(nodes[j].n), Getline(nodes[j].n), +				   "Overloaded method %s ignored,\n", Swig_name_decl(nodes[j].n)); +		      Swig_warning(WARN_LANG_OVERLOAD_CONST, Getfile(nodes[i].n), Getline(nodes[i].n), +				   "using non-const method %s instead.\n", Swig_name_decl(nodes[i].n)); +		    } else { +		      if (!Getattr(nodes[j].n, "overload:ignore")) { +			Swig_warning(WARN_LANG_OVERLOAD_IGNORED, Getfile(nodes[j].n), Getline(nodes[j].n), +				     "Overloaded method %s ignored,\n", Swig_name_decl(nodes[j].n)); +			Swig_warning(WARN_LANG_OVERLOAD_IGNORED, Getfile(nodes[i].n), Getline(nodes[i].n), +				     "using %s instead.\n", Swig_name_decl(nodes[i].n)); +		      } +		    } +		  } +		  nodes[j].error = 1; +		} else if (!SwigType_isconst(d1) && SwigType_isconst(d2)) { +		  differ = 1; +		  if (!nodes[j].error) { +		    if (script_lang_wrapping) { +		      Swig_warning(WARN_LANG_OVERLOAD_CONST, Getfile(nodes[j].n), Getline(nodes[j].n), +				   "Overloaded method %s ignored,\n", Swig_name_decl(nodes[j].n)); +		      Swig_warning(WARN_LANG_OVERLOAD_CONST, Getfile(nodes[i].n), Getline(nodes[i].n), +				   "using non-const method %s instead.\n", Swig_name_decl(nodes[i].n)); +		    } else { +		      if (!Getattr(nodes[j].n, "overload:ignore")) { +			Swig_warning(WARN_LANG_OVERLOAD_IGNORED, Getfile(nodes[j].n), Getline(nodes[j].n), +				     "Overloaded method %s ignored,\n", Swig_name_decl(nodes[j].n)); +			Swig_warning(WARN_LANG_OVERLOAD_IGNORED, Getfile(nodes[i].n), Getline(nodes[i].n), +				     "using %s instead.\n", Swig_name_decl(nodes[i].n)); +		      } +		    } +		  } +		  nodes[j].error = 1; +		} +	      } +	      Delete(dq1); +	      Delete(dq2); +	    } +	  } +	  if (!differ) { +	    if (!nodes[j].error) { +	      if (script_lang_wrapping) { +		Swig_warning(WARN_LANG_OVERLOAD_SHADOW, Getfile(nodes[j].n), Getline(nodes[j].n), +			     "Overloaded method %s effectively ignored,\n", Swig_name_decl(nodes[j].n)); +		Swig_warning(WARN_LANG_OVERLOAD_SHADOW, Getfile(nodes[i].n), Getline(nodes[i].n), +			     "as it is shadowed by %s.\n", Swig_name_decl(nodes[i].n)); +	      } else { +		if (!Getattr(nodes[j].n, "overload:ignore")) { +		  Swig_warning(WARN_LANG_OVERLOAD_IGNORED, Getfile(nodes[j].n), Getline(nodes[j].n), +			       "Overloaded method %s ignored,\n", Swig_name_decl(nodes[j].n)); +		  Swig_warning(WARN_LANG_OVERLOAD_IGNORED, Getfile(nodes[i].n), Getline(nodes[i].n), +			       "using %s instead.\n", Swig_name_decl(nodes[i].n)); +		} +	      } +	      nodes[j].error = 1; +	    } +	  } +	} +      } +    } +  } +  List *result = NewList(); +  { +    int i; +    for (i = 0; i < nnodes; i++) { +      if (nodes[i].error) +	Setattr(nodes[i].n, "overload:ignore", "1"); +      Append(result,nodes[i].n); +    } +  } +  return result; +} + +void R::dispatchFunction(Node *n) { +  Wrapper *f = NewWrapper(); +  String *symname = Getattr(n, "sym:name"); +  String *nodeType = Getattr(n, "nodeType"); +  bool constructor = (!Cmp(nodeType, "constructor")); + +  String *sfname = NewString(symname); + +  if (constructor) +    Replace(sfname, "new_", "", DOH_REPLACE_FIRST); + +  Printf(f->def, +	 "`%s` <- function(...) {", sfname); +  if (debugMode) { +    Swig_print_node(n); +  } +  List *dispatch = Swig_overload_rank(n, true); +  int   nfunc = Len(dispatch); +  Printv(f->code, +	 "argtypes <- mapply(class, list(...));\n", +	 "argv <- list(...);\n", +	 "argc <- length(argtypes);\n", +	 "f <- NULL;\n", NIL); + +  Printf(f->code, "# dispatch functions %d\n", nfunc); +  int cur_args = -1; +  bool first_compare = true; +  for (int i=0; i < nfunc; i++) { +    Node *ni = Getitem(dispatch,i); +    Parm *pi = Getattr(ni,"wrap:parms"); +    int num_arguments = emit_num_arguments(pi); + +    String *overname = Getattr(ni,"sym:overname"); +    if (cur_args != num_arguments) { +      if (cur_args != -1) { +	Printv(f->code, "} else ", NIL); +      } +      Printf(f->code, "if (argc == %d) {", num_arguments); +      cur_args = num_arguments; +      first_compare = true; +    } +    Parm *p; +    int j; +    if (num_arguments > 0) { +      if (!first_compare) { +	Printv(f->code, " else ", NIL); +      } else { +	first_compare = false; +      } +      Printv(f->code, "if (", NIL); +      for (p = pi, j = 0 ; j < num_arguments ; j++) { +	if (debugMode) { +	  Swig_print_node(p); +	} +	String *tm = Swig_typemap_lookup("rtype", p, "", 0); +	if (tm) { +	  replaceRClass(tm, Getattr(p, "type")); +	} + +	String *tmcheck = Swig_typemap_lookup("rtypecheck", p, "", 0); +	if (tmcheck) { +	  String *tmp_argtype = NewStringf("argtypes[%d]", j+1); +	  Replaceall(tmcheck, "$argtype", tmp_argtype); +	  String *tmp_arg = NewStringf("argv[[%d]]", j+1); +	  Replaceall(tmcheck, "$arg", tmp_arg); +	  replaceRClass(tmcheck, Getattr(p, "type")); +	  if (debugMode) { +	    Printf(stdout, "<rtypecheck>%s\n", tmcheck); +	  } +	  if (num_arguments == 1) { +	    Printf(f->code, "%s", tmcheck); +	  } else { +	    Printf(f->code, "%s(%s)", j == 0 ? "" : " && ", tmcheck); +	  } +	  p = Getattr(p, "tmap:in:next"); +	  Delete(tmp_arg); +	  Delete(tmp_argtype); +	  continue; +	} +	// Below should be migrated into rtypecheck typemaps +	// Preparation for this has started by warning in swig-4.1.1 for "numeric", "integer", "character" typemaps +	// For swig-4.2: remove the code block below and uncomment typemaps marked 'Replacement rtypecheck typemaps' in rtype.swg. +	// There is a slight difference in output as the typemap approach fixes some bugs due to a missing type resolution below +	if (tm) { +	  String *tmcode = NULL; +	  Printf(f->code, "%s", j == 0 ? "" : " && "); +	  if (num_arguments != 1) +	    Printf(f->code, "("); +	  Printf(f->code, " "); +	  if (Strcmp(tm, "numeric") == 0) { +	    tmcode = NewString("is.numeric($arg)"); +	  } else if (Strcmp(tm, "integer") == 0) { +	    tmcode = NewString("(is.integer($arg) || is.numeric($arg))"); +	  } else if (Strcmp(tm, "character") == 0) { +	    tmcode = NewString("is.character($arg)"); +	  } else { +	    if (SwigType_ispointer(Getattr(p, "type"))) +	      Printf(f->code, "extends(argtypes[%d], '%s') || is.null(argv[[%d]])", j+1, tm, j+1); +	    else +	      Printf(f->code, "extends(argtypes[%d], '%s') && length(argv[[%d]]) == 1", j+1, tm, j+1); +	  } +	  if (tmcode) { +	    if (!SwigType_ispointer(Getattr(p, "type"))) +	      Printf(tmcode, " && length($arg) == 1"); +	    Swig_warning(WARN_R_MISSING_RTYPECHECK_TYPEMAP, input_file, line_number, +			 "Optional rtypecheck code is deprecated. Add the following typemap to fix as the next version of SWIG will not work without it: %%typemap(\"rtypecheck\") %s %%{ %s %%}\n", +			 SwigType_str(Getattr(p, "type"), 0), tmcode); +	    String *tmp_arg = NewStringf("argv[[%d]]", j+1); +	    Replaceall(tmcode, "$arg", tmp_arg); +	    Printv(f->code, tmcode, NIL); +	    Delete(tmp_arg); +	  } +	  Printf(f->code, " "); +	  if (num_arguments != 1) +	    Printf(f->code, ")"); +	  Delete(tmcode); +	} +	p = Getattr(p, "tmap:in:next"); +      } +      Printf(f->code, ") { f <- %s%s; }\n", sfname, overname); +    } else { +      Printf(f->code, "f <- %s%s; ", sfname, overname); +    } +  } +  if (cur_args != -1) { +    Printf(f->code, "};\n"); +  } +  Printf(f->code, "if (is.null(f)) {\n" +      "stop(\"cannot find overloaded function for %s with argtypes (\"," +      "toString(argtypes),\")\");\n" +      "}", sfname); +  Printv(f->code, ";\nf(...)", NIL); +  Printv(f->code, ";\n}", NIL); +  Wrapper_print(f, sfile); +  Printv(sfile, "# Dispatch function\n", NIL); +  DelWrapper(f); +} + +/*-------------------------------------------------------------- + +* --------------------------------------------------------------*/ + +int R::functionWrapper(Node *n) { +  String *fname = Getattr(n, "name"); +  String *iname = Getattr(n, "sym:name"); +  String *type = Getattr(n, "type"); + +  if (debugMode) { +    Printf(stdout, +	   "<functionWrapper> %s %s %s\n", fname, iname, type); +  } +  String *overname = 0; +  String *nodeType = Getattr(n, "nodeType"); +  bool constructor = (!Cmp(nodeType, "constructor")); +  bool destructor = (!Cmp(nodeType, "destructor")); + +  String *sfname = NewString(iname); + +  if (constructor) +    Replace(sfname, "new_", "", DOH_REPLACE_FIRST); + +  if (Getattr(n,"sym:overloaded")) { +    overname = Getattr(n,"sym:overname"); +    Append(sfname, overname); +  } + +  if (debugMode) +    Printf(stdout, +	   "<functionWrapper> processing parameters\n"); + + +  ParmList *l = Getattr(n, "parms"); +  Parm *p; +  String *tm; + +  p = l; +  while(p) { +    SwigType *resultType = Getattr(p, "type"); +    if (expandTypedef(resultType) && +	SwigType_istypedef(resultType)) { +      SwigType *resolved = +	SwigType_typedef_resolve_all(resultType); +      if (expandTypedef(resolved)) { +        if (debugMode) { +          Printf(stdout, "Setting type: %s\n", resolved); +        } +	Setattr(p, "type", Copy(resolved)); +      } +    } +    p = nextSibling(p); +  } + +  String *unresolved_return_type = +    Copy(type); +  if (expandTypedef(type) && +      SwigType_istypedef(type)) { +    SwigType *resolved = +      SwigType_typedef_resolve_all(type); +    if (debugMode) +      Printf(stdout, "<functionWrapper> resolved %s\n", Copy(unresolved_return_type)); +    if (expandTypedef(resolved)) { +      type = Copy(resolved); +      Setattr(n, "type", type); +    } +  } +  if (debugMode) +    Printf(stdout, "<functionWrapper> unresolved_return_type %s\n", unresolved_return_type); +  if(processing_member_access_function) { +    if (debugMode) +      Printf(stdout, "<functionWrapper memberAccess> '%s' '%s' '%s' '%s'\n", fname, iname, member_name, class_name); + +    if(opaqueClassDeclaration) +      return SWIG_OK; + + +    /* Add the name of this member to a list for this class_name. +       We will dump all these at the end. */ + +    bool isSet = GetFlag(n, "memberset") ? true : false; + +    String *tmp = NewString(isSet ? Swig_name_set(NSPACE_TODO, class_name) : Swig_name_get(NSPACE_TODO, class_name)); + +    List *memList = Getattr(ClassMemberTable, tmp); +    if(!memList) { +      memList = NewList(); +      Append(memList, class_name); +      Setattr(ClassMemberTable, tmp, memList); +    } +    Delete(tmp); +    Append(memList, member_name); +    Append(memList, iname); +  } + +  int i; +  int nargs; + +  String *wname = Swig_name_wrapper(iname); + +  if(overname) +    Append(wname, overname); +  Setattr(n,"wrap:name", wname); + +  Wrapper *f = NewWrapper(); +  Wrapper *sfun = NewWrapper(); + +  int isVoidReturnType = (Strcmp(type, "void") == 0); +  // Need to use the unresolved return type since +  // typedef resolution removes the const which causes a +  // mismatch with the function action +  emit_return_variable(n, unresolved_return_type, f); + +  SwigType *rtype = Getattr(n, "type"); +  int addCopyParam = 0; + +  if(!isVoidReturnType) +    addCopyParam = addCopyParameter(rtype); + +  if (debugMode) +    Printf(stdout, "Adding a .copy argument to %s for %s = %s\n", +	   iname, type, addCopyParam ? "yes" : "no"); + +  Printv(f->def, "SWIGEXPORT SEXP\n", wname, " ( ", NIL); + +  Printf(sfun->def, "# Start of %s\n", iname); +  Printv(sfun->def, "\n`", sfname, "` = function(", NIL); + +  if(outputNamespaceInfo) {//XXX Need to be a little more discriminating +    if (constructor) { +      String *niname = Copy(iname); +      Replace(niname, "new_", "", DOH_REPLACE_FIRST); +      addNamespaceFunction(niname); +      Delete(niname); +    } else { +      addNamespaceFunction(iname); +    } +  } + +  Swig_typemap_attach_parms("scoercein", l, f); +  Swig_typemap_attach_parms("scoerceout", l, f); +  Swig_typemap_attach_parms("scheck", l, f); + +  emit_parameter_variables(l, f); +  emit_attach_parmmaps(l,f); +  Setattr(n,"wrap:parms",l); + +  nargs = emit_num_arguments(l); + +  Wrapper_add_local(f, "r_nprotect", "unsigned int r_nprotect = 0"); +  Wrapper_add_localv(f, "r_ans", "SEXP", "r_ans = R_NilValue", NIL); +  Wrapper_add_localv(f, "r_vmax", "VMAXTYPE", "r_vmax = vmaxget()", NIL); + +  String *sargs = NewString(""); + + +  String *s_inputTypes = NewString(""); +  String *s_inputMap = NewString(""); +  bool inFirstArg = true; +  bool inFirstType = true; +  Parm *curP; +  for (p =l, i = 0 ; i < nargs ; i++) { + +    while (checkAttribute(p, "tmap:in:numinputs", "0")) { +      p = Getattr(p, "tmap:in:next"); +    } + +    SwigType *tt = Getattr(p, "type"); +    int nargs = -1; +    String *funcptr_name = processType(tt, p, &nargs); + +    //      SwigType *tp = Getattr(p, "type"); +    String   *name  = Getattr(p,"name"); +    String   *lname  = Getattr(p,"lname"); + +    // R keyword renaming +    if (name) { +      if (Swig_name_warning(p, 0, name, 0)) { +	name = 0; +      } else { +	/* If we have a :: in the parameter name because we are accessing a static member of a class, say, then +	   we need to remove that prefix. */ +	while (Strstr(name, "::")) { +	  //XXX need to free. +	  name = NewStringf("%s", Strchr(name, ':') + 2); +	  if (debugMode) +	    Printf(stdout, "+++  parameter name with :: in it %s\n", name); +	} +      } +    } +    if (!name || Len(name) == 0) +      name = NewStringf("s_arg%d", i+1); + +    name = replaceInitialDash(name); + +    if (!Strncmp(name, "arg", 3)) { +      name = Copy(name); +      Insert(name, 0, "s_"); +    } + +    if(processing_variable) { +      name = Copy(name); +      Insert(name, 0, "s_"); +    } + +    if(!Strcmp(name, fname)) { +      name = Copy(name); +      Insert(name, 0, "s_"); +    } + +    Printf(sargs, "%s, ", name); + +    String *tm; +    if((tm = Getattr(p, "tmap:scoercein"))) { +      Replaceall(tm, "$input", name); +      replaceRClass(tm, Getattr(p, "type")); + +      if(funcptr_name) { +	//XXX need to get this to return non-zero +	if(nargs == -1) +	  nargs = getFunctionPointerNumArgs(p, tt); + +	String *snargs = NewStringf("%d", nargs); +	Printv(sfun->code, "if(is.function(", name, ")) {", "\n", +	       "assert('...' %in% names(formals(", name, +	       ")) || length(formals(", name, ")) >= ", snargs, ");\n} ", NIL); +	Delete(snargs); + +	Printv(sfun->code, "else {\n", +	       "if(is.character(", name, ")) {\n", +	       name, " = getNativeSymbolInfo(", name, ");", +	       "\n};\n", +	       "if(is(", name, ", \"NativeSymbolInfo\")) {\n", +	       name, " = ", name, "$address", ";\n};\n", +	       "if(is(", name, ", \"ExternalReference\")) {\n", +	       name, " = ", name, "@ref;\n}\n", +	       "}; \n", +	       NIL); +      } else { +	Printf(sfun->code, "%s\n", tm); +      } +    } + +    Printv(sfun->def, inFirstArg ? "" : ", ", name, NIL); + +    if ((tm = Getattr(p,"tmap:scheck"))) { + +      Replaceall(tm,"$input", name); +      replaceRClass(tm, Getattr(p, "type")); +      Printf(sfun->code,"%s\n",tm); +    } + + + +    curP = p; +    if ((tm = Getattr(p,"tmap:in"))) { + +      Replaceall(tm,"$input", name); + +      if (Getattr(p,"wrap:disown") || (Getattr(p,"tmap:in:disown"))) { +	Replaceall(tm,"$disown","SWIG_POINTER_DISOWN"); +      } else { +	Replaceall(tm,"$disown","0"); +      } + +      if(funcptr_name) { +	/* have us a function pointer */ +	Printf(f->code, "if(TYPEOF(%s) != CLOSXP) {\n", name); +	Replaceall(tm,"$R_class", ""); +      } else { +	replaceRClass(tm, Getattr(p, "type")); +      } + + +      Printf(f->code,"%s\n",tm); +      if(funcptr_name) +	Printf(f->code, "} else {\n%s = %s;\nR_SWIG_pushCallbackFunctionData(%s, NULL);\n}\n", +	       lname, funcptr_name, name); +      Printv(f->def, inFirstArg ? "" : ", ", "SEXP ", name, NIL); +      if (Len(name) != 0) +	inFirstArg = false; +      p = Getattr(p,"tmap:in:next"); + +    } else { +      p = nextSibling(p); +    } + + +    tm = Swig_typemap_lookup("rtype", curP, "", 0); +    if(tm) { +      replaceRClass(tm, Getattr(curP, "type")); +    } +    Printf(s_inputTypes, "%s'%s'", inFirstType ? "" : ", ", tm); +    Printf(s_inputMap, "%s%s='%s'", inFirstType ? "" : ", ", name, tm); +    inFirstType = false; + +    if(funcptr_name) +      Delete(funcptr_name); +  } /* end of looping over parameters. */ + +  if(addCopyParam) { +    Printf(sfun->def, "%s.copy = FALSE", nargs > 0 ? ", " : ""); +    Printf(f->def, "%sSEXP s_swig_copy", nargs > 0 ? ", " : ""); + +    Printf(sargs, "as.logical(.copy), "); +  } + +  Printv(f->def, ")\n{\n", NIL); +  // SWIG_fail in R leads to a call to Rf_error() which calls longjmp() +  // which means the destructors of any live function-local C++ objects won't +  // get run.  To avoid this happening, we wrap almost everything in the +  // function in a block, and end that right before Rf_error() at which +  // point those destructors will get called. +  if (CPlusPlus) Append(f->def, "{\n"); + +  Printv(sfun->def, ")\n{\n", NIL); + + +  /* Insert cleanup code */ +  String *cleanup = NewString(""); +  for (p = l; p;) { +    if ((tm = Getattr(p, "tmap:freearg"))) { +      if (tm && (Len(tm) != 0)) { +        Printv(cleanup, tm, "\n", NIL); +      } +      p = Getattr(p, "tmap:freearg:next"); +    } else { +      p = nextSibling(p); +    } +  } + +  String *outargs = NewString(""); +  int numOutArgs = isVoidReturnType ? -1 : 0; +  for(p = l, i = 0; p; i++) { +    if((tm = Getattr(p, "tmap:argout"))) { +      //       String *lname =  Getattr(p, "lname"); +      numOutArgs++; +      String *pos = NewStringf("%d", numOutArgs); +      Replaceall(tm,"$result", "r_ans"); +      Replaceall(tm,"$n", pos); // The position into which to store the answer. +      Replaceall(tm,"$arg", Getattr(p, "emit:input")); +      Replaceall(tm,"$input", Getattr(p, "emit:input")); +      Replaceall(tm,"$owner", "0"); + + +      Printf(outargs, "%s\n", tm); +      p = Getattr(p,"tmap:argout:next"); +    } else +      p = nextSibling(p); +  } + +  String *actioncode = emit_action(n); + +  /* Deal with the explicit return value. */ +  if ((tm = Swig_typemap_lookup_out("out", n, Swig_cresult_name(), f, actioncode))) { +    SwigType *retType = Getattr(n, "type"); +     +    Replaceall(tm,"$1", Swig_cresult_name()); +    Replaceall(tm,"$result", "r_ans"); +    if (debugMode){ +      Printf(stdout, "Calling replace D: %s, %s, %s\n", retType, n, tm); +    } +    replaceRClass(tm, retType); + +    if (GetFlag(n,"feature:new")) { +      Replaceall(tm, "$owner", "SWIG_POINTER_OWN"); +    } else { +      Replaceall(tm,"$owner", "0"); +    } + +    Printf(f->code, "%s\n", tm); + +  } else { +    Swig_warning(WARN_TYPEMAP_OUT_UNDEF, input_file, line_number, +		 "Unable to use return type %s in function %s.\n", SwigType_str(type, 0), fname); +  } + + +  if(Len(outargs)) { +    Wrapper_add_local(f, "R_OutputValues", "SEXP R_OutputValues"); + +    String *tmp = NewString(""); +    if(!isVoidReturnType) +      Printf(tmp, "Rf_protect(r_ans);\n"); + +    Printf(tmp, "Rf_protect(R_OutputValues = Rf_allocVector(VECSXP,%d));\nr_nprotect += %d;\n", +	   numOutArgs + !isVoidReturnType, +	   isVoidReturnType ? 1 : 2); + +    if(!isVoidReturnType) +      Printf(tmp, "SET_VECTOR_ELT(R_OutputValues, 0, r_ans);\n"); +    Printf(tmp, "r_ans = R_OutputValues;\n"); + +    Insert(outargs, 0, tmp); +    Delete(tmp); + + + +    Printv(f->code, outargs, NIL); +    Delete(outargs); + +  } + +  /* Output cleanup code */ +  int need_cleanup = Len(cleanup) != 0; +  if (need_cleanup) { +    Printv(f->code, cleanup, NIL); +  } + +  /* Look to see if there is any newfree cleanup code */ +  if (GetFlag(n, "feature:new")) { +    if ((tm = Swig_typemap_lookup("newfree", n, Swig_cresult_name(), 0))) { +      Printf(f->code, "%s\n", tm); +    } +  } + +  /* See if there is any return cleanup code */ +  if ((tm = Swig_typemap_lookup("ret", n, Swig_cresult_name(), 0))) { +    Printf(f->code, "%s\n", tm); +    Delete(tm); +  } + +  Printv(f->code, UnProtectWrapupCode, NIL); + +  /*If the user gave us something to convert the result in  */ +  if ((tm = Swig_typemap_lookup("scoerceout", n, Swig_cresult_name(), sfun))) { +    Replaceall(tm,"$result","ans"); +    if (debugMode) { +      Printf(stdout, "Calling replace B: %s, %s, %s\n", Getattr(n, "type"), Getattr(n, "sym:name"), getNSpace()); +    } +    replaceRClass(tm, Getattr(n, "type")); +    Chop(tm); +  } + + +  Printv(sfun->code, ";", (Len(tm) ? "ans = " : ""), ".Call('", wname, +	 "', ", sargs, "PACKAGE='", Rpackage, "');\n", NIL); +  if(Len(tm)) +    { +      Printf(sfun->code, "%s\n\n", tm); +      if (constructor) +	{ +	  String *finalizer = NewString(iname); +	  Replace(finalizer, "new_", "", DOH_REPLACE_FIRST); +	  Printf(sfun->code, "reg.finalizer(ans@ref, delete_%s);\n", finalizer); +	} +      Printf(sfun->code, "ans\n"); +    } + +  if (destructor) +    Printv(f->code, "R_ClearExternalPtr(self);\n", NIL); + +  Printv(f->code, "return r_ans;\n", NIL); +   +  /* Error handling code */ +  Printv(f->code, "fail: SWIGUNUSED;\n", NIL); +  if (need_cleanup) { +    Printv(f->code, cleanup, NIL); +  } +  if (CPlusPlus) Append(f->code, "}\n"); +  Printv(f->code, "  Rf_error(\"%s %s\", SWIG_ErrorType(SWIG_lasterror_code), SWIG_lasterror_msg);\n", NIL); +  Printv(f->code, "  return R_NilValue;\n", NIL); +  Delete(cleanup); +   +  Printv(f->code, "}\n", NIL); +  Printv(sfun->code, "\n}", NIL); + +  /* Substitute the function name */ +  Replaceall(f->code,"$symname",iname); + +  Wrapper_print(f, f_wrapper); +  Wrapper_print(sfun, sfile); + +  Printf(sfun->code, "\n# End of %s\n", iname); +  tm = Swig_typemap_lookup("rtype", n, "", 0); +  if(tm) { +    SwigType *retType = Getattr(n, "type"); +    if (debugMode) { +      Printf(stdout, "Calling replace C: %s\n", Copy(retType)); +    } +    replaceRClass(tm, retType); +  } + +  Printv(sfile, "attr(`", sfname, "`, 'returnType') = '", +	 isVoidReturnType ? "void" : (tm ? tm : ""), +	 "'\n", NIL); + +  if(nargs > 0) +    Printv(sfile, "attr(`", sfname, "`, \"inputTypes\") = c(", +	   s_inputTypes, ")\n", NIL); +  Printv(sfile, "class(`", sfname, "`) = c(\"SWIGFunction\", class('", +	 sfname, "'))\n\n", NIL); + +  if (memoryProfile) { +    Printv(sfile, "memory.profile()\n", NIL); +  } +  if (aggressiveGc) { +    Printv(sfile, "gc()\n", NIL); +  } + +  // Printv(sfile, "setMethod('", name, "', '", name, "', ", iname, ")\n\n\n"); + + + +  /* If we are dealing with a method in an C++ class, then +     add the name of the R function and its definition. +     XXX need to figure out how to store the Wrapper if possible in the hash/list. +     Would like to be able to do this so that we can potentially insert +  */ +  if(processing_member_access_function || processing_class_member_function) { +    String *method_type = R_MEMBER_NORMAL; +    if (GetFlag(n, "memberset")) { +      method_type = R_MEMBER_SET; +    } else if (GetFlag(n, "memberget")) { +      method_type = R_MEMBER_GET; +    } +    addAccessor(member_name, sfun, iname, method_type); +  } + +  if (Getattr(n, "sym:overloaded") && +      !Getattr(n, "sym:nextSibling")) { +    dispatchFunction(n); +  } + +  addRegistrationRoutine(wname, addCopyParam ? nargs +1 : nargs); + +  DelWrapper(f); +  DelWrapper(sfun); + +  Delete(sargs); +  Delete(sfname); +  return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * R::constantWrapper() + * ---------------------------------------------------------------------- */ + +int R::constantWrapper(Node *n) { +  (void) n; +  // TODO +  return SWIG_OK; +} + +/*-------------------------------------------------------------- + * Add the specified routine name to the collection of + * generated routines that are called from R functions. + * This is used to register the routines with R for + * resolving symbols. + + * rname - the name of the routine + * nargs - the number of arguments it expects. + * --------------------------------------------------------------*/ + +int R::addRegistrationRoutine(String *rname, int nargs) { +  if(!registrationTable) +    registrationTable = NewHash(); + +  String *el = +    NewStringf("{\"%s\", (DL_FUNC) &%s, %d}", rname, rname, nargs); + +  Setattr(registrationTable, rname, el); + +  return SWIG_OK; +} + +/* ------------------------------------------------------------- + * Write the registration information to an array and + * create the initialization routine for registering + * these. + * --------------------------------------------------------------*/ + +int R::outputRegistrationRoutines(File *out) { +  int i, n; +  if(!registrationTable) +    return(0); +  if(inCPlusMode) +    Printf(out, "#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n"); + +  Printf(out, "#include <R_ext/Rdynload.h>\n\n"); +  if(inCPlusMode) +    Printf(out, "#ifdef __cplusplus\n}\n#endif\n\n"); + +  Printf(out, "SWIGINTERN R_CallMethodDef CallEntries[] = {\n"); + +  List *keys = Keys(registrationTable); +  n = Len(keys); +  for(i = 0; i < n; i++) +    Printf(out, "   %s,\n", Getattr(registrationTable, Getitem(keys, i))); + +  Printf(out, "   {NULL, NULL, 0}\n};\n\n"); + +  if(!noInitializationCode) { +    if (inCPlusMode) +      Printv(out, "extern \"C\" ", NIL); +    { /* R allows pckage names to have '.' in the name, which is not allowed in C++ var names +	 we simply replace all occurrences of '.' with '_' to construct the var name */ +      String * Rpackage_sane = Copy(Rpackage); +      Replace(Rpackage_sane, ".", "_", DOH_REPLACE_ANY); +      Printf(out, "SWIGEXPORT void R_init_%s(DllInfo *dll) {\n", Rpackage_sane); +      Delete(Rpackage_sane); +    } +    Printf(out, "%sR_registerRoutines(dll, NULL, CallEntries, NULL, NULL);\n", tab4); +    if(Len(s_init_routine)) { +      Printf(out, "\n%s\n", s_init_routine); +    } +    Printf(out, "}\n"); +  } + +  return n; +} + + + +/* ------------------------------------------------------------- + * Process a struct, union or class declaration in the source code, + * or an anonymous typedef struct + * --------------------------------------------------------------*/ + +//XXX What do we need to do here - +// Define an S4 class to refer to this. + +void R::registerClass(Node *n) { +  String *name = Getattr(n, "name"); + +  if (debugMode) +    Swig_print_node(n); +  String *sname = NewStringf("_p%s", SwigType_manglestr(name)); +  if(!Getattr(SClassDefs, sname)) { +    Setattr(SClassDefs, sname, sname); +    String *base; + +    if (CPlusPlus && (Strcmp(nodeType(n), "class") == 0)) { +      base = NewString(""); +      List *l = Getattr(n, "bases"); +      if(Len(l)) { +	Printf(base, "c("); +	for(int i = 0; i < Len(l); i++) { +	  registerClass(Getitem(l, i)); +	  Printf(base, "'_p%s'%s", +		 SwigType_manglestr(Getattr(Getitem(l, i), "name")), +		 i < Len(l)-1 ? ", " : ""); +	} +	Printf(base, ")"); +      } else { +	base = NewString("'C++Reference'"); +      } +    } else +      base = NewString("'ExternalReference'"); + +    Printf(s_classes, "setClass('%s', contains = %s)\n", sname, base); +    Delete(base); +  } +} + +int R::classDeclaration(Node *n) { + +  String *name = Getattr(n, "name"); +  String *kind = Getattr(n, "kind"); + +  if (debugMode) +    Swig_print_node(n); +  registerClass(n); + + +  /* If we have a typedef union { ... } U, then we never get to see the typedef +     via a regular call to typedefHandler. Instead, */ +  if(Getattr(n, "unnamed") && Getattr(n, "storage") && Strcmp(Getattr(n, "storage"), "typedef") == 0 +     && Getattr(n, "tdname") && Strcmp(Getattr(n, "tdname"), name) == 0) { +    if (debugMode) +      Printf(stdout, "Typedef in the class declaration for %s\n", name); +    //        typedefHandler(n); +  } + +  bool opaque = GetFlag(n, "feature:opaque") ? true : false; + +  if(opaque) +    opaqueClassDeclaration = name; + +  int status = Language::classDeclaration(n); + +  opaqueClassDeclaration = NULL; + + +  if (class_member_function_types) { + +    // collect the "set" methods +    List *class_set_membernames   = filterMemberList(class_member_function_types,  +                                                     class_member_function_membernames, R_MEMBER_SET, true); +    List *class_set_functionnames = filterMemberList(class_member_function_types,  +                                                     class_member_function_names, R_MEMBER_SET, true); +    // this one isn't used - collecting to keep code simpler +    List *class_set_functiontypes = filterMemberList(class_member_function_types,  +                                                     class_member_function_types, R_MEMBER_SET, true); + +    // collect the others +    List *class_other_membernames   = filterMemberList(class_member_function_types,  +                                                       class_member_function_membernames, R_MEMBER_SET, false); +    List *class_other_functionnames = filterMemberList(class_member_function_types,  +                                                       class_member_function_names, R_MEMBER_SET, false); +    List *class_other_functiontypes = filterMemberList(class_member_function_types,  +                                                       class_member_function_types, R_MEMBER_SET, false); + +    if (Len(class_other_membernames) > 0) { +      OutputMemberReferenceMethod(name, 0, class_other_membernames, class_other_functionnames, class_other_functiontypes, sfile); +    } +    if (Len(class_set_membernames) > 0) { +      OutputMemberReferenceMethod(name, 1, class_set_membernames, class_set_functionnames, class_set_functiontypes, sfile); +    } +    Delete(class_set_membernames); +    Delete(class_set_functionnames); +    Delete(class_set_functiontypes); +    Delete(class_other_membernames); +    Delete(class_other_functionnames); +    Delete(class_other_functiontypes); + } + +  if (class_member_function_types) { +    Delete(class_member_function_types); +    class_member_function_types = NULL; +    Delete(class_member_function_names); +    class_member_function_names = NULL; +    Delete(class_member_function_membernames); +    class_member_function_membernames = NULL; +    Delete(class_member_function_wrappernames); +    class_member_function_wrappernames = NULL; +   } +  if (Getattr(n, "has_destructor")) { +    Printf(sfile, "setMethod('delete', '_p%s', function(obj) {delete%s(obj)})\n", getRClassName(name), getRClassName(name)); + +  } +  if(!opaque && !Strcmp(kind, "struct") && copyStruct) { + +    String *def = +      NewStringf("setClass(\"%s\",\n%srepresentation(\n", name, tab4); +    bool firstItem = true; + +    for(Node *c = firstChild(n); c; ) { +      String *elName; +      String *tp; + +      elName = Getattr(c, "name"); + +      String *elKind = Getattr(c, "kind"); +      if (!Equal(elKind, "variable")) { +	c = nextSibling(c); +	continue; +      } +      if (!Len(elName)) { +	c = nextSibling(c); +	continue; +      } +      tp = Swig_typemap_lookup("rtype", c, "", 0); +      if(!tp) { +	c = nextSibling(c); +	continue; +      } +      if (Strstr(tp, "R_class")) { +	c = nextSibling(c); +	continue; +      } +      if (Strcmp(tp, "character") && +	  Strstr(Getattr(c, "decl"), "p.")) { +	c = nextSibling(c); +	continue; +      } + +      if (!firstItem) { +	Printf(def, ",\n"); +      } +      //	    else +      //XXX How can we tell if this is already done. +      //	      SwigType_push(elType, elDecl); +	 +	 +      // returns ""  tp = processType(elType, c, NULL); +      //	    Printf(stdout, "<classDeclaration> elType %p\n", elType); +      //	    tp = getRClassNameCopyStruct(Getattr(c, "type"), 1); + +      String *elNameT = replaceInitialDash(elName); +      Printf(def, "%s%s = \"%s\"", tab8, elNameT, tp); +      firstItem = false; +      Delete(tp); +      Delete(elNameT); +      c = nextSibling(c); +    } +    Printf(def, "),\n%scontains = \"RSWIGStruct\")\n", tab8); +    Printf(s_classes, "%s\n\n# End class %s\n\n", def, name); + +    generateCopyRoutines(n); + +    Delete(def); +  } + +  return status; +} + + + +/* ------------------------------------------------------------- + * Create the C routines that copy an S object of the class given + * by the given struct definition in Node *n to the C value + * and also the routine that goes from the C routine to an object + * of this S class. + * --------------------------------------------------------------*/ + +/*XXX +  Clean up the toCRef - make certain the names are correct for the types, etc. +  in all cases. +*/ + +int R::generateCopyRoutines(Node *n) { +  Wrapper *copyToR = NewWrapper(); +  Wrapper *copyToC = NewWrapper(); + +  String *name = Getattr(n, "name"); +  String *tdname = Getattr(n, "tdname"); +  String *kind = Getattr(n, "kind"); +  String *type; + +  if(Len(tdname)) { +    type = Copy(tdname); +  } else { +    type = NewStringf("%s %s", kind, name); +  } + +  String *mangledName = SwigType_manglestr(name); + +  if (debugMode) +    Printf(stdout, "generateCopyRoutines:  name = %s, %s\n", name, type); + +  Printf(copyToR->def, "CopyToR%s = function(value, obj = new(\"%s\"))\n{\n", +	 mangledName, name); +  Printf(copyToC->def, "CopyToC%s = function(value, obj)\n{\n", +	 mangledName); + +  Node *c = firstChild(n); + +  for(; c; c = nextSibling(c)) { +    String *elName = Getattr(c, "name"); +    if (!Len(elName)) { +      continue; +    } +    String *elKind = Getattr(c, "kind"); +    if (!Equal(elKind, "variable")) { +      continue; +    } + +    String *tp = Swig_typemap_lookup("rtype", c, "", 0); +    if(!tp) { +      continue; +    } +    if (Strstr(tp, "R_class")) { +      continue; +    } +    if (Strcmp(tp, "character") && +	Strstr(Getattr(c, "decl"), "p.")) { +      continue; +    } + + +    /* The S functions to get and set the member value. */ +    String *elNameT = replaceInitialDash(elName); +    Printf(copyToR->code, "obj@%s = value$%s;\n", elNameT, elNameT); +    Printf(copyToC->code, "obj$%s = value@%s;\n", elNameT, elNameT); +    Delete(elNameT); +  } +  Printf(copyToR->code, "obj;\n}\n\n"); +  String *rclassName = getRClassNameCopyStruct(type, 0); // without the Ref. +  Printf(sfile, "# Start definition of copy functions & methods for %s\n", rclassName); + +  Wrapper_print(copyToR, sfile); +  Printf(copyToC->code, "obj\n}\n\n"); +  Wrapper_print(copyToC, sfile); + + +  Printf(sfile, "# Start definition of copy methods for %s\n", rclassName); +  Printf(sfile, "setMethod('copyToR', '_p%s', CopyToR%s);\n", mangledName, +	 mangledName); +  Printf(sfile, "setMethod('copyToC', '%s', CopyToC%s);\n\n", rclassName, +	 mangledName); + +  Printf(sfile, "# End definition of copy methods for %s\n", rclassName); +  Printf(sfile, "# End definition of copy functions & methods for %s\n", rclassName); + +  String *m = NewStringf("%sCopyToR", name); +  addNamespaceMethod(m); +  char *tt = Char(m);  tt[Len(m)-1] = 'C'; +  addNamespaceMethod(m); +  Delete(m); +  Delete(rclassName); +  Delete(mangledName); +  DelWrapper(copyToR); +  DelWrapper(copyToC); + +  return SWIG_OK; +} + + + +/* ------------------------------------------------------------- + *  Called when there is a typedef to be invoked. + * + *  XXX Needs to be enhanced or split to handle the case where we have a + *  typedef within a classDeclaration emission because the struct/union/etc. + *  is anonymous. + * --------------------------------------------------------------*/ + +int R::typedefHandler(Node *n) { +  SwigType *tp = Getattr(n, "type"); +  String *type = Getattr(n, "type"); +  if (debugMode) +    Printf(stdout, "<typedefHandler> %s\n", Getattr(n, "name")); + +  processType(tp, n); + +  if(Strncmp(type, "struct ", 7) == 0) { +    String *name = Getattr(n, "name"); +    char *trueName = Char(type); +    trueName += 7; +    if (debugMode) +      Printf(stdout, "<typedefHandler> Defining S class %s\n", trueName); +    Printf(s_classes, "setClass('_p%s', contains = 'ExternalReference')\n", +	   SwigType_manglestr(name)); +  } + +  return Language::typedefHandler(n); +} + + + +/* -------------------------------------------------------------- + * Called when processing a field in a "class", i.e. struct, union or + * actual class.  We set a state variable so that we can correctly + * interpret the resulting functionWrapper() call and understand that + * it is for a field element. + * --------------------------------------------------------------*/ + +int R::membervariableHandler(Node *n) { +  SwigType *t = Getattr(n, "type"); +  processType(t, n, NULL); +  processing_member_access_function = 1; +  member_name = Getattr(n,"sym:name"); +  if (debugMode) +    Printf(stdout, "<membervariableHandler> name = %s, sym:name = %s\n", +	   Getattr(n, "name"), member_name); + +  int status(Language::membervariableHandler(n)); + +  if(!opaqueClassDeclaration && debugMode) +    Printf(stdout, "<membervariableHandler> %s %s\n", Getattr(n, "name"), Getattr(n, "type")); + +  processing_member_access_function = 0; +  member_name = NULL; + +  return status; +} + + +/* +  This doesn't seem to get used so leave it out for the moment. +*/ +String * R::runtimeCode() { +  String *s = Swig_include_sys("rrun.swg"); +  if (!s) { +    Printf(stdout, "*** Unable to open 'rrun.swg'\n"); +    s = NewString(""); +  } +  return s; +} + +/*---------------------------------------------------------------------- + * replaceSpecialVariables() + *--------------------------------------------------------------------*/ + +void R::replaceSpecialVariables(String *method, String *tm, Parm *parm) { +  (void)method; +  SwigType *type = Getattr(parm, "type"); +  replaceRClass(tm, type); +} + + +/* ----------------------------------------------------------------------- + * Called when SWIG wants to initialize this + * We initialize anythin we want here. + * Most importantly, tell SWIG where to find the files (e.g. r.swg) for this module. + * Use Swig_mark_arg() to tell SWIG that it is understood and not to + * throw an error. + * --------------------------------------------------------------*/ + +void R::main(int argc, char *argv[]) { +  init(); +  Preprocessor_define("SWIGR 1", 0); +  SWIG_library_directory("r"); +  SWIG_config_file("r.swg"); +  debugMode = false; +  copyStruct = true; +  memoryProfile = false; +  aggressiveGc = false; +  inCPlusMode = false; +  outputNamespaceInfo = false; +  noInitializationCode = false; + +  this->Argc = argc; +  this->Argv = argv; + +  allow_overloading();// can we support this? + +  for(int i = 0; i < argc; i++) { +    if(strcmp(argv[i], "-package") == 0) { +      Swig_mark_arg(i); +      i++; +      Swig_mark_arg(i); +      Rpackage = argv[i]; +    } else if(strcmp(argv[i], "-dll") == 0) { +      Swig_mark_arg(i); +      i++; +      Swig_mark_arg(i); +      DllName = argv[i]; +    } else if(strcmp(argv[i], "-help") == 0) { +      showUsage(); +    } else if(strcmp(argv[i], "-namespace") == 0) { +      outputNamespaceInfo = true; +      Swig_mark_arg(i); +    } else if(!strcmp(argv[i], "-no-init-code")) { +      noInitializationCode = true; +      Swig_mark_arg(i); +    } else if(!strcmp(argv[i], "-c++")) { +      inCPlusMode = true; +      Swig_mark_arg(i); +      Printf(s_classes, "setClass('C++Reference', contains = 'ExternalReference')\n"); +    } else if(!strcmp(argv[i], "-debug")) { +      debugMode = true; +      Swig_mark_arg(i); +    } else if (!strcmp(argv[i],"-copystruct")) { +      copyStruct = true; +      Swig_mark_arg(i); +    } else if (!strcmp(argv[i], "-nocopystruct")) { +      copyStruct = false; +      Swig_mark_arg(i); +    } else if (!strcmp(argv[i], "-memoryprof")) { +      memoryProfile = true; +      Swig_mark_arg(i); +    } else if (!strcmp(argv[i], "-nomemoryprof")) { +      memoryProfile = false; +      Swig_mark_arg(i); +    } else if (!strcmp(argv[i], "-aggressivegc")) { +      aggressiveGc = true; +      Swig_mark_arg(i); +    } else if (!strcmp(argv[i], "-noaggressivegc")) { +      aggressiveGc = false; +      Swig_mark_arg(i); +    } else if (strcmp(argv[i], "-cppcast") == 0) { +      Printf(stderr, "Deprecated command line option: %s. This option is now always on.\n", argv[i]); +      Swig_mark_arg(i); +    } else if (strcmp(argv[i], "-nocppcast") == 0) { +      Printf(stderr, "Deprecated command line option: %s. This option is no longer supported.\n", argv[i]); +      Swig_mark_arg(i); +      Exit(EXIT_FAILURE); +    } + +    if (debugMode) { +      Swig_typemap_search_debug_set(); +      Swig_typemap_used_debug_set(); +      Swig_typemap_register_debug_set(); +      Swig_file_debug_set(); +    } +    /// copyToR copyToC functions. + +  } +} + +/* ----------------------------------------------------------------------- + * Could make this work for String or File and then just store the resulting string + * rather than the collection of arguments and argc. + * ----------------------------------------------------------------------- */ +int R::outputCommandLineArguments(File *out) +{ +  if(Argc < 1 || !Argv || !Argv[0]) +    return(-1); + +  Printf(out, "\n##   Generated via the command line invocation:\n##\t"); +  for(int i = 0; i < Argc ; i++) { +    Printf(out, " %s", Argv[i]); +  } +  Printf(out, "\n\n\n"); + +  return Argc; +} + + + +/* How SWIG instantiates an object from this module. +   See swigmain.cxx */ +extern "C" +Language *swig_r(void) { +  return new R(); +} + + + + +/* ----------------------------------------------------------------------- + * Needs to be reworked. + *----------------------------------------------------------------------- */ +String * R::processType(SwigType *t, Node *n, int *nargs) { +  //XXX Need to handle typedefs, e.g. +  //  a type which is a typedef  to a function pointer. + +  SwigType *tmp = Getattr(n, "tdname"); +  if (debugMode) +    Printf(stdout, "processType %s (tdname = %s)(SwigType = %s)\n", Getattr(n, "name"), tmp, Copy(t)); + +  SwigType *td = t; +  if (expandTypedef(t) && +      SwigType_istypedef(t)) { +    SwigType *resolved = +      SwigType_typedef_resolve_all(t); +    if (expandTypedef(resolved)) { +      td = Copy(resolved); +    } +  } + +  if(!td) { +    int count = 0; +    String *b = getRTypeName(t, &count); +    if(count && b && !Getattr(SClassDefs, b)) { +      if (debugMode) +	Printf(stdout, "<processType> Defining class %s\n",  b); + +      Printf(s_classes, "setClass('%s', contains = 'ExternalReference')\n", b); +      Setattr(SClassDefs, b, b); +    } + +  } + + +  if(td) +    t = td; + +  if(SwigType_isfunctionpointer(t)) { +    if (debugMode) +      Printf(stdout, +	     "<processType> Defining pointer handler %s\n",  t); + +    String *tmp = createFunctionPointerHandler(t, n, nargs); +    return tmp; +  } + +    return NULL; +} + + +/* ----------------------------------------------------------------------- + * enumValue() + * This method will return a string with an enum value to use in from R when  + * setting up an enum variable + * ------------------------------------------------------------------------ */ + +String *R::enumValue(Node *n) { +  String *symname = Getattr(n, "sym:name"); +  String *value = Getattr(n, "value"); +  String *newsymname = 0; + +  Node *parent = parentNode(n); +  symname = Getattr(n, "sym:name"); +   +  // parent enumtype has namespace mangled in +  String *etype = Getattr(parent, "enumtype"); +  // we have to directly call the c wrapper function, as the +  // R wrapper to the enum is designed to be used after the enum +  // structures have been created on the R side. This means +  // that we'll need to construct a .Call expression + +  // change the type for variableWrapper +  if (debugMode) { +    Printf(stdout, "<enumValue> type set: %s\n", etype); +  } + +  Setattr(n, "type", etype); + +  if (!getCurrentClass()) { +    newsymname = Swig_name_member(0, Getattr(parent, "sym:name"), symname); +    // Strange hack to change the name +    Setattr(n, "name", Getattr(n, "value")); +    Setattr(n, "sym:name", newsymname); +    variableWrapper(n); +    value = Swig_name_get(NSPACE_TODO, newsymname); +  } else { +    String *enumClassPrefix = getEnumClassPrefix(); +    newsymname = Swig_name_member(0, enumClassPrefix, symname); +    Setattr(n, "name", Getattr(n, "value")); +    Setattr(n, "sym:name", newsymname); +    variableWrapper(n); +    value = Swig_name_get(NSPACE_TODO, newsymname); +  } +  value = Swig_name_wrapper(value); +  Replace(value, "_wrap", "R_swig", DOH_REPLACE_FIRST); + +  String *valuecall=NewString(""); +  Printv(valuecall, ".Call('", value, "',FALSE, PACKAGE='", Rpackage, "')", NIL); +  Delete(value); +  return valuecall; +} diff --git a/contrib/tools/swig/Source/Modules/ruby.cxx b/contrib/tools/swig/Source/Modules/ruby.cxx new file mode 100644 index 00000000000..0208435f039 --- /dev/null +++ b/contrib/tools/swig/Source/Modules/ruby.cxx @@ -0,0 +1,3470 @@ +/* -----------------------------------------------------------------------------  + * This file is part of SWIG, which is licensed as a whole under version 3  + * (or any later version) of the GNU General Public License. Some additional + * terms also apply to certain portions of SWIG. The full details of the SWIG + * license and copyrights can be found in the LICENSE and COPYRIGHT files + * included with the SWIG source code as distributed by the SWIG developers + * and at https://www.swig.org/legal.html. + * + * ruby.cxx + * + * Ruby language module for SWIG. + * ----------------------------------------------------------------------------- */ + +#include "swigmod.h" +#include "cparse.h" +#include <ctype.h> +#include <string.h> +#include <limits.h>		/* for INT_MAX */ + +#define SWIG_PROTECTED_TARGET_METHODS 1 + +class RClass { +private: +  String *temp; + +public: +  String *name;			/* class name (renamed) */ +  String *cname;		/* original C class/struct name */ +  String *mname;		/* Mangled name */ + +  /** +   * The C variable name used in the SWIG-generated wrapper code to refer to +   * this class; usually it is of the form "SwigClassXXX.klass", where SwigClassXXX +   * is a swig_class struct instance and klass is a member of that struct. +   */ +  String *vname; + +  /** +   * The C variable name used in the SWIG-generated wrapper code to refer to +   * the module that implements this class's methods (when we're trying to +   * support C++ multiple inheritance). Usually it is of the form +   * "SwigClassClassName.mImpl", where SwigClassXXX is a swig_class struct instance +   * and mImpl is a member of that struct. +   */ +  String *mImpl; + +  String *type; +  String *prefix; +  String *init; + + +  int constructor_defined; +  int destructor_defined; + +   RClass() { +    temp = NewString(""); +    name = NewString(""); +    cname = NewString(""); +    mname = NewString(""); +    vname = NewString(""); +    mImpl = NewString(""); +    type = NewString(""); +    prefix = NewString(""); +    init = NewString(""); +    constructor_defined = 0; +    destructor_defined = 0; +  } +   +  ~RClass() { +    Delete(name); +    Delete(cname); +    Delete(vname); +    Delete(mImpl); +    Delete(mname); +    Delete(type); +    Delete(prefix); +    Delete(init); +    Delete(temp); +  } + +  void set_name(const_String_or_char_ptr cn, const_String_or_char_ptr rn, const_String_or_char_ptr valn) { +    /* Original C/C++ class (or struct) name */ +    Clear(cname); +    Append(cname, cn); + +    /* Mangled name */ +    Delete(mname); +    mname = Swig_name_mangle(cname); + +    /* Renamed class name */ +    Clear(name); +    Append(name, valn); + +    /* Variable name for the VALUE that refers to the Ruby Class object */ +    Clear(vname); +    Printf(vname, "SwigClass%s.klass", name); + +    /* Variable name for the VALUE that refers to the Ruby Class object */ +    Clear(mImpl); +    Printf(mImpl, "SwigClass%s.mImpl", name); + +    /* Prefix */ +    Clear(prefix); +    Printv(prefix, (rn ? rn : cn), "_", NIL); +  } + +  char *strip(const_String_or_char_ptr s) { +    Clear(temp); +    if (Strncmp(s, prefix, Len(prefix)) == 0) { +      Append(temp, Char(s) + Len(prefix)); +    } else { +      Append(temp, s); +    } +    return Char(temp); +  } +}; + + +/* flags for the make_autodoc function */ +namespace { +enum autodoc_t { +  AUTODOC_CLASS, +  AUTODOC_CTOR, +  AUTODOC_DTOR, +  AUTODOC_STATICFUNC, +  AUTODOC_FUNC, +  AUTODOC_METHOD, +  AUTODOC_GETTER, +  AUTODOC_SETTER, +  AUTODOC_NONE +}; +} + +static const char *usage = "\ +Ruby Options (available with -ruby)\n\ +     -autorename     - Enable renaming of classes and methods to follow Ruby coding standards\n\ +     -globalmodule   - Wrap everything into the global module\n\ +     -initname <name>- Set entry function to Init_<name> (used by `require')\n\ +     -minherit       - Attempt to support multiple inheritance\n\ +     -noautorename   - Disable renaming of classes and methods (default)\n\ +     -prefix <name>  - Set a prefix <name> to be prepended to all names\n\ +"; + + +#define RCLASS(hash, name) (RClass*)(Getattr(hash, name) ? Data(Getattr(hash, name)) : 0) +#define SET_RCLASS(hash, name, klass) Setattr(hash, name, NewVoid(klass, 0)) + + +class RUBY:public Language { +private: + +  String *module; +  String *modvar; +  String *feature; +  String *prefix; +  int current; +  Hash *classes;		/* key=cname val=RClass */ +  RClass *klass;		/* Currently processing class */ +  Hash *special_methods;	/* Python style special method name table */ + +  File *f_directors; +  File *f_directors_h; +  File *f_directors_helpers; +  File *f_begin; +  File *f_runtime; +  File *f_runtime_h; +  File *f_header; +  File *f_wrappers; +  File *f_init; +  File *f_initbeforefunc; + +  bool useGlobalModule; +  bool multipleInheritance; + +  // Wrap modes +  enum WrapperMode { +    NO_CPP, +    MEMBER_FUNC, +    CONSTRUCTOR_ALLOCATE, +    CONSTRUCTOR_INITIALIZE, +    DESTRUCTOR, +    MEMBER_VAR, +    CLASS_CONST, +    STATIC_FUNC, +    STATIC_VAR +  }; + +  /* ------------------------------------------------------------ +   * autodoc level declarations +   * ------------------------------------------------------------ */ + +  enum autodoc_l { +    NO_AUTODOC = -2,		// no autodoc +    STRING_AUTODOC = -1,	// use provided string +    NAMES_AUTODOC = 0,		// only parameter names +    TYPES_AUTODOC = 1,		// parameter names and types +    EXTEND_AUTODOC = 2,		// extended documentation and parameter names +    EXTEND_TYPES_AUTODOC = 3	// extended documentation and parameter types + names +  }; + +  autodoc_t last_mode; +  String*   last_autodoc; + +  autodoc_l autodoc_level(String *autodoc) { +    autodoc_l dlevel = NO_AUTODOC; +    char *c = Char(autodoc); +    if (c) { +      if (isdigit(c[0])) { +	dlevel = (autodoc_l) atoi(c); +      } else { +	if (strcmp(c, "extended") == 0) { +	  dlevel = EXTEND_AUTODOC; +	} else { +	  dlevel = STRING_AUTODOC; +	} +      } +    } +    return dlevel; +  } + + + +  /* ------------------------------------------------------------ +   * have_docstring() +   *    Check if there is a docstring directive and it has text, +   *    or there is an autodoc flag set +   * ------------------------------------------------------------ */ + +  bool have_docstring(Node *n) { +    String *str = Getattr(n, "feature:docstring"); +    return (str && Len(str) > 0) || (Getattr(n, "feature:autodoc") && !GetFlag(n, "feature:noautodoc")); +  } + +  /* ------------------------------------------------------------ +   * docstring() +   *    Get the docstring text, stripping off {} if necessary, +   *    and enclose in triple double quotes.  If autodoc is also +   *    set then it will build a combined docstring. +   * ------------------------------------------------------------ */ + +  String *docstring(Node *n, autodoc_t ad_type) { + +    String *str = Getattr(n, "feature:docstring"); +    bool have_ds = (str && Len(str) > 0); +    bool have_auto = (Getattr(n, "feature:autodoc") && !GetFlag(n, "feature:noautodoc")); +    String *autodoc = NULL; +    String *doc = NULL; + +    if (have_ds) { +      char *t = Char(str); +      if (*t == '{') { +	Delitem(str, 0); +	Delitem(str, DOH_END); +      } +    } + +    if (have_auto) { +      autodoc = make_autodoc(n, ad_type); +      have_auto = (autodoc && Len(autodoc) > 0); +    } + +    if (have_auto || have_ds) +      doc = NewString("/*"); + +    if (have_auto && have_ds) {	// Both autodoc and docstring are present +      Printv(doc, "\n", autodoc, "\n", str, "\n", NIL); +    } else if (!have_auto && have_ds) {	// only docstring +      Printv(doc, str, NIL); +    } else if (have_auto && !have_ds) {	// only autodoc +      Printv(doc, "\n", autodoc, "\n", NIL); +    } else { +      doc = NewString(""); +    } + +    if (have_auto || have_ds) +      Append(doc, "*/\n"); + +    // Save the generated strings in the parse tree in case they are used later +    // by post processing tools +    Setattr(n, "ruby:docstring", doc); +    Setattr(n, "ruby:autodoc", autodoc); +    return doc; +  } + +  /* ----------------------------------------------------------------------------- +   * addMissingParameterNames() +   *  For functions that have not had nameless parameters set in the Language class. +   * +   * Inputs:  +   *   plist - entire parameter list +   *   arg_offset - argument number for first parameter +   * Side effects: +   *   The "lname" attribute in each parameter in plist will be contain a parameter name +   * ----------------------------------------------------------------------------- */ + +  void addMissingParameterNames(Node* n, ParmList *plist, int arg_offset) { +    Parm *p = plist; +    int i = arg_offset; +    while (p) { +      if (!Getattr(p, "lname")) { +	String *name = makeParameterName(n, p, i); +	Setattr(p, "lname", name); +	Delete(name); +      } +      i++; +      p = nextSibling(p); +    } +  } + +  /* ------------------------------------------------------------ +   * make_autodocParmList() +   *   Generate the documentation for the function parameters +   * ------------------------------------------------------------ */ + +  String *make_autodocParmList(Node *n, bool showTypes) { +    String *doc = NewString(""); +    String *pdocs = 0; +    ParmList *plist = CopyParmList(Getattr(n, "parms")); +    Parm *p; +    Parm *pnext; +    int lines = 0; +    int arg_num = is_wrapping_class() ? 1 : 0; +    const int maxwidth = 80; + +    addMissingParameterNames(n, plist, arg_num); // for $1_name substitutions done in Swig_typemap_attach_parms + +    Swig_typemap_attach_parms("in", plist, 0); +    Swig_typemap_attach_parms("doc", plist, 0); + +    if (Strcmp(ParmList_protostr(plist), "void") == 0) { +      //No parameters actually +      return doc; +    } + +    for (p = plist; p; p = pnext, arg_num++) { + +      String *tm = Getattr(p, "tmap:in"); +      if (tm) { +	pnext = Getattr(p, "tmap:in:next"); +	if (checkAttribute(p, "tmap:in:numinputs", "0")) { +	  continue; +	} +      } else { +	pnext = nextSibling(p); +      } + +      String *name = 0; +      String *type = 0; +      String *value = 0; +      String *pdoc = Getattr(p, "tmap:doc"); +      if (pdoc) { +	name = Getattr(p, "tmap:doc:name"); +	type = Getattr(p, "tmap:doc:type"); +	value = Getattr(p, "tmap:doc:value"); +      } + +      // Note: the generated name should be consistent with that in kwnames[] +      String *made_name = 0; +      if (!name) { +	name = made_name = makeParameterName(n, p, arg_num); +      } + +      type = type ? type : Getattr(p, "type"); +      value = value ? value : Getattr(p, "value"); + +      if (SwigType_isvarargs(type)) +	break; + +      // Skip the 'self' parameter which in ruby is implicit +      if ( Cmp(name, "self") == 0 ) +	continue; + +      // Make __p parameters just p (as used in STL) +      Replace( name, "__", "", DOH_REPLACE_FIRST ); + +      if (Len(doc)) { +	// add a comma to the previous one if any +	Append(doc, ", "); + +	// Do we need to wrap a long line? +	if ((Len(doc) - lines * maxwidth) > maxwidth) { +	  Printf(doc, "\n%s", tab4); +	  lines += 1; +	} +      } + +      // Do the param type too? +      Node *nn = classLookup(Getattr(p, "type")); +      String *type_str = nn ? Copy(Getattr(nn, "sym:name")) : SwigType_str(type, 0); +      if (showTypes) +	Printf(doc, "%s ", type_str); + +      Append(doc, name); +      if (pdoc) { +	if (!pdocs) +	  pdocs = NewString("Parameters:\n"); +	Printf(pdocs, "    %s.\n", pdoc); +      } + +      if (value) { +	String *new_value = convertValue(value, Getattr(p, "type")); +	if (new_value) { +	  value = new_value; +	} else { +	  Node *lookup = Swig_symbol_clookup(value, 0); +	  if (lookup) +	    value = Getattr(lookup, "sym:name"); +	} +	Printf(doc, "=%s", value); +      } +      Delete(type_str); +      Delete(made_name); +    } +    if (pdocs) +      Setattr(n, "feature:pdocs", pdocs); +    Delete(plist); +    return doc; +  } + +  /* ------------------------------------------------------------ +   * make_autodoc() +   *    Build a docstring for the node, using parameter and other +   *    info in the parse tree.  If the value of the autodoc +   *    attribute is "0" then do not include parameter types, if +   *    it is "1" (the default) then do.  If it has some other +   *    value then assume it is supplied by the extension writer +   *    and use it directly. +   * ------------------------------------------------------------ */ + +  String *make_autodoc(Node *n, autodoc_t ad_type) { +    int extended = 0; +    // If the function is overloaded then this function is called +    // for the last one.  Rewind to the first so the docstrings are +    // in order. +    while (Getattr(n, "sym:previousSibling")) +      n = Getattr(n, "sym:previousSibling"); + +    Node *pn = Swig_methodclass(n); +    String* super_names = NewString("");  +    String* class_name = Getattr(pn, "sym:name") ;  + +    if ( !class_name ) { +      class_name = NewString(""); +    } else { +      class_name = Copy(class_name); +      List *baselist = Getattr(pn, "bases"); +      if (baselist && Len(baselist)) { +	Iterator base = First(baselist); +	while (base.item && GetFlag(base.item, "feature:ignore")) { +	  base = Next(base); +	} + +	int count = 0; +	for ( ;base.item; ++count) { +	  if ( count ) Append(super_names, ", "); +	  String *basename = Getattr(base.item, "sym:name"); + +	  String* basenamestr = NewString(basename); +	  Node* parent = parentNode(base.item); +	  while (parent) +	  { +	    String *parent_name = Copy( Getattr(parent, "sym:name") ); +	    if ( !parent_name ) { +	      Node* mod = Getattr(parent, "module"); +	      if ( mod ) +		parent_name = Copy( Getattr(mod, "name") ); +	      if ( parent_name ) +		(Char(parent_name))[0] = (char)toupper((Char(parent_name))[0]); +	    } +	    if ( parent_name ) { +	      Insert(basenamestr, 0, "::"); +	      Insert(basenamestr, 0, parent_name); +	      Delete(parent_name); +	    } +	    parent = parentNode(parent); +	  } + +	  Append(super_names, basenamestr ); +	  Delete(basenamestr); +	  base = Next(base); +	} +      } +    } +    String* full_name; +    if ( module ) { +      full_name = NewString(module); +      if (Len(class_name) > 0) +       	Append(full_name, "::"); +    } +    else +      full_name = NewString(""); +    Append(full_name, class_name); + +    String* symname = Getattr(n, "sym:name"); +    if ( Getattr( special_methods, symname ) ) +      symname = Getattr( special_methods, symname ); + +    String* methodName = NewString(full_name); +    Append(methodName, symname); + + +    // Each overloaded function will try to get documented, +    // so we keep the name of the last overloaded function and its type. +    // Documenting just from functionWrapper() is not possible as +    // sym:name has already been changed to include the class name +    if ( last_mode == ad_type && Cmp(methodName, last_autodoc) == 0 ) { +      Delete(full_name); +      Delete(class_name); +      Delete(super_names); +      Delete(methodName); +      return NewString(""); +    } + + +    last_mode    = ad_type; +    last_autodoc = Copy(methodName); + +    String *doc = NewString(""); +    int counter = 0; +    bool skipAuto = false; +    Node* on = n; +    for ( ; n; ++counter ) { +      String *type_str = NULL; +      skipAuto = false; +      bool showTypes = false; +      String *autodoc = Getattr(n, "feature:autodoc"); +      autodoc_l dlevel = autodoc_level(autodoc); +      switch (dlevel) { +      case NO_AUTODOC: +	break; +      case NAMES_AUTODOC: +	showTypes = false; +	break; +      case TYPES_AUTODOC: +	showTypes = true; +	break; +      case EXTEND_AUTODOC: +	extended = 1; +	showTypes = false; +	break; +      case EXTEND_TYPES_AUTODOC: +	extended = 1; +	showTypes = true; +	break; +      case STRING_AUTODOC: +	skipAuto = true; +	break; +      } + +      SwigType *type = Getattr(n, "type"); + +      if (type) { +	if (Strcmp(type, "void") == 0) { +	  type_str = NULL; +	} else { +	  SwigType *qt = SwigType_typedef_resolve_all(type); +	  if (SwigType_isenum(qt)) { +	    type_str = NewString("int"); +	  } else { +	    Node *nn = classLookup(type); +	    type_str = nn ? Copy(Getattr(nn, "sym:name")) : SwigType_str(type, 0); +	  } +	} +      } + +      if (counter == 0) { +	switch (ad_type) { +	case AUTODOC_CLASS: +	  Printf(doc, "  Document-class: %s", full_name); +	  if ( Len(super_names) > 0 ) +	    Printf( doc, " < %s", super_names); +	  Append(doc, "\n\n"); +	  break; +	case AUTODOC_CTOR: + 	  Printf(doc, "  Document-method: %s.new\n\n", full_name); +	  break; + +	case AUTODOC_DTOR: +	  break; + +	case AUTODOC_STATICFUNC: + 	  Printf(doc, "  Document-method: %s.%s\n\n", full_name, symname); +	  break; + +	case AUTODOC_FUNC: +	case AUTODOC_METHOD: +	case AUTODOC_GETTER: + 	  Printf(doc, "  Document-method: %s.%s\n\n", full_name, symname); +	  break; +	case AUTODOC_SETTER: + 	  Printf(doc, "  Document-method: %s.%s=\n\n", full_name, symname); +	  break; +	case AUTODOC_NONE: +	  break; +	} +      } + +      if (skipAuto) { +	if ( counter == 0 ) Printf(doc, "  call-seq:\n"); +	switch( ad_type ) +	  { +	  case AUTODOC_STATICFUNC: +	  case AUTODOC_FUNC: +	  case AUTODOC_METHOD: +	  case AUTODOC_GETTER: +	    { +	      String *paramList = make_autodocParmList(n, showTypes); +	      if (Len(paramList)) +		Printf(doc, "    %s(%s)", symname, paramList); +	      else +		Printf(doc, "    %s", symname); +	      if (type_str) +		Printf(doc, " -> %s", type_str); +	      break; +	    } +	  case AUTODOC_SETTER: +	    { +	      Printf(doc, "    %s=(x)", symname); +	      if (type_str) +	       	Printf(doc, " -> %s", type_str); +	      break; +	    } +	  default: +	    break; +	  } +      } else { +	switch (ad_type) { +	case AUTODOC_CLASS: +	  { +	    // Only do the autodoc if there isn't a docstring for the class +	    String *str = Getattr(n, "feature:docstring"); +	    if (counter == 0 && (str == 0 || Len(str) == 0)) { +	      if (CPlusPlus) { +		Printf(doc, "  Proxy of C++ %s class", full_name); +	      } else { +		Printf(doc, "  Proxy of C %s struct", full_name); +	      } +	    } +	  } +	  break; +	case AUTODOC_CTOR: +	  if (counter == 0) +	    Printf(doc, "  call-seq:\n"); +	  if (Strcmp(class_name, symname) == 0) { +	    String *paramList = make_autodocParmList(n, showTypes); +	    if (Len(paramList)) +	      Printf(doc, "    %s.new(%s)", class_name, paramList); +	    else +	      Printf(doc, "    %s.new", class_name); +	  } else { +	    Printf(doc, "    %s.new(%s)", class_name, make_autodocParmList(n, showTypes)); +	  } +	  break; + +	case AUTODOC_DTOR: +	  break; + +	case AUTODOC_STATICFUNC: +	case AUTODOC_FUNC: +	case AUTODOC_METHOD: +	case AUTODOC_GETTER: +	  { +	    if (counter == 0) +	      Printf(doc, "  call-seq:\n"); +	    String *paramList = make_autodocParmList(n, showTypes); +	    if (Len(paramList)) +	      Printf(doc, "    %s(%s)", symname, paramList); +	    else +	      Printf(doc, "    %s", symname); +	    if (type_str) +	      Printf(doc, " -> %s", type_str); +	    break; +	  } +	case AUTODOC_SETTER: +	  { +	    Printf(doc, "  call-seq:\n"); +	    Printf(doc, "    %s=(x)", symname); +	    if (type_str) +	      Printf(doc, " -> %s", type_str); +	    break; +	  } +	case AUTODOC_NONE: +	  break; +	} +      } + +      // if it's overloaded then get the next decl and loop around again +      n = Getattr(n, "sym:nextSibling"); +      if (n) +	Append(doc, "\n"); +      Delete(type_str); +    } + +    Printf(doc, "\n\n"); +    if (!skipAuto) { +      switch (ad_type) { +      case AUTODOC_CLASS: +      case AUTODOC_DTOR: +	break; +      case AUTODOC_CTOR: +	Printf(doc, "Class constructor.\n"); +	break; +      case AUTODOC_STATICFUNC: +	Printf(doc, "A class method.\n"); +	break; +      case AUTODOC_FUNC: +	Printf(doc, "A module function.\n"); +	break; +      case AUTODOC_METHOD: +	Printf(doc, "An instance method.\n"); +	break; +      case AUTODOC_GETTER: +	Printf(doc, "Get value of attribute.\n"); +	break; +      case AUTODOC_SETTER: +	Printf(doc, "Set new value for attribute.\n"); +	break; +      case AUTODOC_NONE: +	break; +      } +    } + + +    n = on; +    while ( n ) { +      String *autodoc = Getattr(n, "feature:autodoc"); +      autodoc_l dlevel = autodoc_level(autodoc); + +      switch (dlevel) { +      case NO_AUTODOC: +      case NAMES_AUTODOC: +      case TYPES_AUTODOC: +	extended = 0; +	break; +      case STRING_AUTODOC: +	extended = 2; +	Replaceall( autodoc, "$class", class_name ); +	Printv(doc, autodoc, ".", NIL); +	break; +      case EXTEND_AUTODOC: +      case EXTEND_TYPES_AUTODOC: +	extended = 1; +	break; +      } + + +      if (extended) { +	String *pdocs = Getattr(n, "feature:pdocs"); +	if (pdocs) { +	  Printv(doc, "\n\n", pdocs, NULL); +	  break; +	} +	if ( extended == 2 ) break; +      } +      n = Getattr(n, "sym:nextSibling"); +    } + +    Delete(full_name); +    Delete(class_name); +    Delete(super_names); +    Delete(methodName); + +    return doc; +  } + +  /* ------------------------------------------------------------ +   * convertValue() +   *    Check if string v can be a Ruby value literal, +   *    (eg. number or string), or translate it to a Ruby literal. +   * ------------------------------------------------------------ */ +  String *convertValue(String *v, SwigType *t) { +    if (v && Len(v) > 0) { +      char fc = (Char(v))[0]; +      if (('0' <= fc && fc <= '9') || '\'' == fc || '"' == fc) { +	/* number or string (or maybe NULL pointer) */ +	if (SwigType_ispointer(t) && Strcmp(v, "0") == 0) +	  return NewString("None"); +	else +	  return v; +      } +      if (Strcmp(v, "NULL") == 0 || Strcmp(v, "nullptr") == 0) +	return SwigType_ispointer(t) ? NewString("nil") : NewString("0"); +      if (Strcmp(v, "true") == 0 || Strcmp(v, "TRUE") == 0) +	return NewString("True"); +      if (Strcmp(v, "false") == 0 || Strcmp(v, "FALSE") == 0) +	return NewString("False"); +    } +    return 0; +  } + +public: + +  /* --------------------------------------------------------------------- +   * RUBY() +   * +   * Initialize member data +   * --------------------------------------------------------------------- */ +  RUBY() : +    module(0), +    modvar(0), +    feature(0), +    prefix(0), +    current(0), +    classes(0), +    klass(0), +    special_methods(0), +    f_directors(0), +    f_directors_h(0), +    f_directors_helpers(0), +    f_begin(0), +    f_runtime(0), +    f_runtime_h(0), +    f_header(0), +    f_wrappers(0), +    f_init(0), +    f_initbeforefunc(0), +    useGlobalModule(false), +    multipleInheritance(false), +    last_mode(AUTODOC_NONE), +    last_autodoc(NewString("")) { +      current = NO_CPP; +      director_prot_ctor_code = NewString(""); +      Printv(director_prot_ctor_code, +          "if ( $comparison ) { /* subclassed */\n", +          "  $director_new \n", +          "} else {\n", "  rb_raise(rb_eRuntimeError,\"accessing abstract class or protected constructor\"); \n", "  return Qnil;\n", "}\n", NIL); +      director_multiple_inheritance = 0; +      director_language = 1; +    } + +  /* --------------------------------------------------------------------- +   * main() +   * +   * Parse command line options and initializes variables. +   * --------------------------------------------------------------------- */ +   +  virtual void main(int argc, char *argv[]) { + +    int autorename = 0; + +    /* Set location of SWIG library */ +    SWIG_library_directory("ruby"); + +    /* Look for certain command line options */ +    for (int i = 1; i < argc; i++) { +      if (argv[i]) { +	if (strcmp(argv[i], "-initname") == 0) { +	  if (argv[i + 1]) { +	    char *name = argv[i + 1]; +	    feature = NewString(name); +	    Swig_mark_arg(i); +	    Swig_mark_arg(i + 1); +	    i++; +	  } else { +	    Swig_arg_error(); +	  } +	} +	else if (strcmp(argv[i], "-feature") == 0) { +	  fprintf( stderr, "Warning: Ruby -feature option is deprecated, " +		   "please use -initname instead.\n"); +	  if (argv[i + 1]) { +	    char *name = argv[i + 1]; +	    feature = NewString(name); +	    Swig_mark_arg(i); +	    Swig_mark_arg(i + 1); +	    i++; +	  } else { +	    Swig_arg_error(); +	  } +	} else if (strcmp(argv[i], "-globalmodule") == 0) { +	  useGlobalModule = true; +	  Swig_mark_arg(i); +	} else if (strcmp(argv[i], "-minherit") == 0) { +	  multipleInheritance = true; +	  director_multiple_inheritance = 1; +	  Swig_mark_arg(i); +	} else if (strcmp(argv[i], "-autorename") == 0) { +	  autorename = 1; +	  Swig_mark_arg(i); +	} else if (strcmp(argv[i], "-noautorename") == 0) { +	  autorename = 0; +	  Swig_mark_arg(i); +	} else if (strcmp(argv[i], "-prefix") == 0) { +	  if (argv[i + 1]) { +	    char *name = argv[i + 1]; +	    prefix = NewString(name); +	    Swig_mark_arg(i); +	    Swig_mark_arg(i + 1); +	    i++; +	  } else { +	    Swig_arg_error(); +	  } +	} else if (strcmp(argv[i], "-help") == 0) { +	  Printf(stdout, "%s\n", usage); +	} else if (strcmp(argv[i], "-cppcast") == 0) { +	  Printf(stderr, "Deprecated command line option: %s. This option is now always on.\n", argv[i]); +	  Swig_mark_arg(i); +	} else if (strcmp(argv[i], "-nocppcast") == 0) { +	  Printf(stderr, "Deprecated command line option: %s. This option is no longer supported.\n", argv[i]); +	  Swig_mark_arg(i); +	  Exit(EXIT_FAILURE); +	} +      } +    } + +    if (autorename) { +      /* Turn on the autorename mode */ +      Preprocessor_define((DOH *) "SWIG_RUBY_AUTORENAME", 0); +    } + +    /* Add a symbol to the parser for conditional compilation */ +    Preprocessor_define("SWIGRUBY 1", 0); + +    /* Add typemap definitions */ +    SWIG_typemap_lang("ruby"); +    SWIG_config_file("ruby.swg"); +    allow_overloading(); +  } + +  /** +   * Generate initialization code to define the Ruby module(s), +   * accounting for nested modules as necessary. +   */ +  void defineRubyModule() { +    List *modules = Split(module, ':', INT_MAX); +    if (modules != 0 && Len(modules) > 0) { +      String *mv = 0; +      Iterator m; +      m = First(modules); +      while (m.item) { +	if (Len(m.item) > 0) { +	  if (mv != 0) { +	    Printv(f_init, tab4, modvar, " = rb_define_module_under(", modvar, ", \"", m.item, "\");\n", NIL); +	  } else { +	    Printv(f_init, tab4, modvar, " = rb_define_module(\"", m.item, "\");\n", NIL); +	    mv = NewString(modvar); +	  } +	} +	m = Next(m); +      } +      Delete(mv); +      Delete(modules); +    } +  } + +  void registerMagicMethods() { + +    special_methods = NewHash(); + +    /* Python->Ruby style special method name. */ +    /* Basic */ +    Setattr(special_methods, "__repr__", "inspect"); +    Setattr(special_methods, "__str__", "to_s"); +    Setattr(special_methods, "__cmp__", "<=>"); +    Setattr(special_methods, "__hash__", "hash"); +    Setattr(special_methods, "__nonzero__", "nonzero?"); + +    /* Callable */ +    Setattr(special_methods, "__call__", "call"); + +    /* Collection */ +    Setattr(special_methods, "__len__", "length"); +    Setattr(special_methods, "__getitem__", "[]"); +    Setattr(special_methods, "__setitem__", "[]="); + +    /* Operators */ +    Setattr(special_methods, "__add__", "+"); +    Setattr(special_methods, "__pos__", "+@"); +    Setattr(special_methods, "__sub__", "-"); +    Setattr(special_methods, "__neg__", "-@"); +    Setattr(special_methods, "__mul__", "*"); +    Setattr(special_methods, "__div__", "/"); +    Setattr(special_methods, "__mod__", "%"); +    Setattr(special_methods, "__lshift__", "<<"); +    Setattr(special_methods, "__rshift__", ">>"); +    Setattr(special_methods, "__and__", "&"); +    Setattr(special_methods, "__or__", "|"); +    Setattr(special_methods, "__xor__", "^"); +    Setattr(special_methods, "__invert__", "~"); +    Setattr(special_methods, "__lt__", "<"); +    Setattr(special_methods, "__le__", "<="); +    Setattr(special_methods, "__gt__", ">"); +    Setattr(special_methods, "__ge__", ">="); +    Setattr(special_methods, "__eq__", "=="); + +    /* Other numeric */ +    Setattr(special_methods, "__divmod__", "divmod"); +    Setattr(special_methods, "__pow__", "**"); +    Setattr(special_methods, "__abs__", "abs"); +    Setattr(special_methods, "__int__", "to_i"); +    Setattr(special_methods, "__float__", "to_f"); +    Setattr(special_methods, "__coerce__", "coerce"); +  } + +  /* --------------------------------------------------------------------- +   * top() +   * --------------------------------------------------------------------- */ + +  virtual int top(Node *n) { + +    String *mod_docstring = NULL; + +    /** +     * See if any Ruby module options have been specified as options +     * to the %module directive. +     */ +    Node *swigModule = Getattr(n, "module"); +    if (swigModule) { +      Node *options = Getattr(swigModule, "options"); +      if (options) { +	if (Getattr(options, "directors")) { +	  allow_directors(); +	} +	if (Getattr(options, "dirprot")) { +	  allow_dirprot(); +	} +	if (Getattr(options, "ruby_globalmodule")) { +	  useGlobalModule = true; +	} +	if (Getattr(options, "ruby_minherit")) { +	  multipleInheritance = true; +	  director_multiple_inheritance = 1; +	} +	mod_docstring = Getattr(options, "docstring"); +      } +    } + +    /* Set comparison with none for ConstructorToFunction */ + + +    setSubclassInstanceCheck(NewStringf("strcmp(rb_obj_classname(self), classname) != 0")); +    // setSubclassInstanceCheck(NewString("CLASS_OF(self) != cFoo.klass")); + +    /* Initialize all of the output files */ +    String *outfile = Getattr(n, "outfile"); +    String *outfile_h = Getattr(n, "outfile_h"); + +    if (!outfile) { +      Printf(stderr, "Unable to determine outfile\n"); +      Exit(EXIT_FAILURE); +    } + +    f_begin = NewFile(outfile, "w", SWIG_output_files()); +    if (!f_begin) { +      FileErrorDisplay(outfile); +      Exit(EXIT_FAILURE); +    } + +    f_runtime = NewString(""); +    f_init = NewString(""); +    f_header = NewString(""); +    f_wrappers = NewString(""); +    f_directors_h = NewString(""); +    f_directors = NewString(""); +    f_directors_helpers = NewString(""); +    f_initbeforefunc = NewString(""); + +    if (directorsEnabled()) { +      if (!outfile_h) { +        Printf(stderr, "Unable to determine outfile_h\n"); +        Exit(EXIT_FAILURE); +      } +      f_runtime_h = NewFile(outfile_h, "w", SWIG_output_files()); +      if (!f_runtime_h) { +	FileErrorDisplay(outfile_h); +	Exit(EXIT_FAILURE); +      } +    } + +    /* Register file targets with the SWIG file handler */ +    Swig_register_filebyname("header", f_header); +    Swig_register_filebyname("wrapper", f_wrappers); +    Swig_register_filebyname("begin", f_begin); +    Swig_register_filebyname("runtime", f_runtime); +    Swig_register_filebyname("init", f_init); +    Swig_register_filebyname("director", f_directors); +    Swig_register_filebyname("director_h", f_directors_h); +    Swig_register_filebyname("director_helpers", f_directors_helpers); +    Swig_register_filebyname("initbeforefunc", f_initbeforefunc); + +    modvar = 0; +    current = NO_CPP; +    klass = 0; +    classes = NewHash(); + +    registerMagicMethods(); + +    Swig_banner(f_begin); + +    Swig_obligatory_macros(f_runtime, "RUBY"); + +    if (directorsEnabled()) { +      Printf(f_runtime, "#define SWIG_DIRECTORS\n"); +    } + +    Printf(f_runtime, "\n"); + +    /* typedef void *VALUE */ +    SwigType *value = NewSwigType(T_VOID); +    SwigType_add_pointer(value); +    SwigType_typedef(value, "VALUE"); +    Delete(value); + +    /* Set module name */ +    set_module(Char(Getattr(n, "name"))); + +    if (directorsEnabled()) { +      /* Build a version of the module name for use in a C macro name. */ +      String *module_macro = Copy(module); +      Replaceall(module_macro, "::", "__"); + +      Swig_banner(f_directors_h); +      Printf(f_directors_h, "\n"); +      Printf(f_directors_h, "#ifndef SWIG_%s_WRAP_H_\n", module_macro); +      Printf(f_directors_h, "#define SWIG_%s_WRAP_H_\n\n", module_macro); +      Printf(f_directors_h, "namespace Swig {\n"); +      Printf(f_directors_h, "  class Director;\n"); +      Printf(f_directors_h, "}\n\n"); + +      Printf(f_directors_helpers, "/* ---------------------------------------------------\n"); +      Printf(f_directors_helpers, " * C++ director class helpers\n"); +      Printf(f_directors_helpers, " * --------------------------------------------------- */\n\n"); + +      Printf(f_directors, "\n\n"); +      Printf(f_directors, "/* ---------------------------------------------------\n"); +      Printf(f_directors, " * C++ director class methods\n"); +      Printf(f_directors, " * --------------------------------------------------- */\n\n"); +      if (outfile_h) { +	String *filename = Swig_file_filename(outfile_h); +	Printf(f_directors, "#include \"%s\"\n\n", filename); +	Delete(filename); +      } + +      Delete(module_macro); +    } + +    Printf(f_header, "#define SWIG_init    Init_%s\n", feature); +    Printf(f_header, "#define SWIG_name    \"%s\"\n\n", module); + +    if (mod_docstring) { +      if (Len(mod_docstring)) { +	Printf(f_header, "/*\n  Document-module: %s\n\n%s\n*/\n", module, mod_docstring); +      } +      Delete(mod_docstring); +      mod_docstring = NULL; +    } + +    Printf(f_header, "static VALUE %s;\n", modvar); + +    /* Start generating the initialization function */ +    String* docs = docstring(n, AUTODOC_CLASS); +    Printf(f_init, "/*\n%s\n*/", docs ); +    Printv(f_init, "\n", "#ifdef __cplusplus\n", "extern \"C\"\n", "#endif\n", "SWIGEXPORT void Init_", feature, "(void) {\n", "size_t i;\n", "\n", NIL); + +    Printv(f_init, tab4, "SWIG_InitRuntime();\n", NIL); + +    if (!useGlobalModule) +      defineRubyModule(); + +    Printv(f_init, "\n", "SWIG_InitializeModule(0);\n", "for (i = 0; i < swig_module.size; i++) {\n", "SWIG_define_class(swig_module.types[i]);\n", "}\n", NIL); +    Printf(f_init, "\n"); + +    /* Initialize code to keep track of objects */ +    Printf(f_init, "SWIG_RubyInitializeTrackings();\n"); + +    Language::top(n); + +    if (directorsEnabled()) { +      // Insert director runtime into the f_runtime file (make it occur before %header section) +      Swig_insert_file("director_common.swg", f_runtime); +      Swig_insert_file("director.swg", f_runtime); +    } + +    /* Finish off our init function */ +    Printf(f_init, "}\n"); +    SwigType_emit_type_table(f_runtime, f_wrappers); + +    /* Close all of the files */ +    Dump(f_runtime, f_begin); +    Dump(f_header, f_begin); + +    if (directorsEnabled()) { +      Dump(f_directors_helpers, f_begin); +      Dump(f_directors, f_begin); +      Dump(f_directors_h, f_runtime_h); +      Printf(f_runtime_h, "\n"); +      Printf(f_runtime_h, "#endif\n"); +      Delete(f_runtime_h); +    } + +    Dump(f_wrappers, f_begin); +    Dump(f_initbeforefunc, f_begin); +    Wrapper_pretty_print(f_init, f_begin); + +    Delete(f_header); +    Delete(f_wrappers); +    Delete(f_init); +    Delete(f_initbeforefunc); +    Delete(f_runtime); +    Delete(f_begin); + +    return SWIG_OK; +  } + +  /* ----------------------------------------------------------------------------- +   * importDirective() +   * ----------------------------------------------------------------------------- */ + +  virtual int importDirective(Node *n) { +    String *modname = Getattr(n, "module"); +    if (modname) { +      if (prefix) { +	Insert(modname, 0, prefix); +      } + +      List *modules = Split(modname, ':', INT_MAX); +      if (modules && Len(modules) > 0) { +	modname = NewString(""); +	String *last = NULL; +	Iterator m = First(modules); +	while (m.item) { +	  if (Len(m.item) > 0) { +	    if (last) { +	      Append(modname, "/"); +	    } +	    Append(modname, m.item); +	    last = m.item; +	  } +	  m = Next(m); +	} +	Printf(f_init, "rb_require(\"%s\");\n", modname); +	Delete(modname); +      } +      Delete(modules); +    } +    return Language::importDirective(n); +  } + +  /* --------------------------------------------------------------------- +   * set_module(const char *mod_name) +   * +   * Sets the module name.  Does nothing if it's already set (so it can +   * be overridden as a command line option). +   *---------------------------------------------------------------------- */ + +  void set_module(const char *s) { +    String *mod_name = NewString(s); +    if (module == 0) { +      /* Start with the empty string */ +      module = NewString(""); + +      if (prefix) { +	Insert(mod_name, 0, prefix); +      } + +      /* Account for nested modules */ +      List *modules = Split(mod_name, ':', INT_MAX); +      if (modules != 0 && Len(modules) > 0) { +	String *last = 0; +	Iterator m = First(modules); +	while (m.item) { +	  if (Len(m.item) > 0) { +	    String *cap = NewString(m.item); +	    (Char(cap))[0] = (char)toupper((Char(cap))[0]); +	    if (last != 0) { +	      Append(module, "::"); +	    } +	    Append(module, cap); +	    last = m.item; +	  } +	  m = Next(m); +	} +	if (last) { +	  if (feature == 0) { +	    feature = Copy(last); +	  } +	  (Char(last))[0] = (char)toupper((Char(last))[0]); +	  modvar = NewStringf("m%s", last); +	} +      } +      Delete(modules); +    } +    Delete(mod_name); +  } + +  /* -------------------------------------------------------------------------- +   * nativeWrapper() +   * -------------------------------------------------------------------------- */ +  virtual int nativeWrapper(Node *n) { +    String *funcname = Getattr(n, "wrap:name"); +    Swig_warning(WARN_LANG_NATIVE_UNIMPL, input_file, line_number, "Adding native function %s not supported (ignored).\n", funcname); +    return SWIG_NOWRAP; +  } + +  /** +   * Process the comma-separated list of aliases (if any). +   */ +  void defineAliases(Node *n, const_String_or_char_ptr iname) { +    String *aliasv = Getattr(n, "feature:alias"); +    if (aliasv) { +      List *aliases = Split(aliasv, ',', INT_MAX); +      if (aliases && Len(aliases) > 0) { +	Iterator alias = First(aliases); +	while (alias.item) { +	  if (Len(alias.item) > 0) { +	    if (current == NO_CPP) { +	      if (useGlobalModule) { +	        Printv(f_init, tab4, "rb_define_alias(rb_cObject, \"", alias.item, "\", \"", iname, "\");\n", NIL); +	      } else { +	        Printv(f_init, tab4, "rb_define_alias(rb_singleton_class(", modvar, "), \"", alias.item, "\", \"", iname, "\");\n", NIL); +	      } +	    } else if (multipleInheritance) { +	      Printv(klass->init, tab4, "rb_define_alias(", klass->mImpl, ", \"", alias.item, "\", \"", iname, "\");\n", NIL); +	    } else { +	      Printv(klass->init, tab4, "rb_define_alias(", klass->vname, ", \"", alias.item, "\", \"", iname, "\");\n", NIL); +	    } +	  } +	  alias = Next(alias); +	} +      } +      Delete(aliases); +    } +  } + +  /* --------------------------------------------------------------------- +   * create_command(Node *n, char *iname) +   * +   * Creates a new command from a C function. +   *              iname = Name of function in scripting language +   * +   * A note about what "protected" and "private" mean in Ruby: +   * +   * A private method is accessible only within the class or its subclasses, +   * and it is callable only in "function form", with 'self' (implicit or +   * explicit) as a receiver. +   * +   * A protected method is callable only from within its class, but unlike +   * a private method, it can be called with a receiver other than self, such +   * as another instance of the same class. +   * --------------------------------------------------------------------- */ + +  void create_command(Node *n, const_String_or_char_ptr iname) { + +    String *alloc_func = Swig_name_wrapper(iname); +    String *wname = Swig_name_wrapper(iname); +    if (CPlusPlus) { +      Insert(wname, 0, "VALUEFUNC("); +      Append(wname, ")"); +    } +    if (current != NO_CPP) +      iname = klass->strip(iname); +    if (Getattr(special_methods, iname)) { +      iname = GetChar(special_methods, iname); +    } + +    String *s = NewString(""); +    String *temp = NewString(""); + +#ifdef SWIG_PROTECTED_TARGET_METHODS +    const char *rb_define_method = is_public(n) ? "rb_define_method" : "rb_define_protected_method"; +#else +    const char *rb_define_method = "rb_define_method"; +#endif +    switch (current) { +    case MEMBER_FUNC: +      { +	if (multipleInheritance) { +	  Printv(klass->init, tab4, rb_define_method, "(", klass->mImpl, ", \"", iname, "\", ", wname, ", -1);\n", NIL); +	} else { +	  Printv(klass->init, tab4, rb_define_method, "(", klass->vname, ", \"", iname, "\", ", wname, ", -1);\n", NIL); +	} +      } +      break; +    case CONSTRUCTOR_ALLOCATE: +      Printv(s, tab4, "rb_define_alloc_func(", klass->vname, ", ", alloc_func, ");\n", NIL); +      Replaceall(klass->init, "$allocator", s); +      break; +    case CONSTRUCTOR_INITIALIZE: +      Printv(s, tab4, rb_define_method, "(", klass->vname, ", \"initialize\", ", wname, ", -1);\n", NIL); +      Replaceall(klass->init, "$initializer", s); +      break; +    case MEMBER_VAR: +      Append(temp, iname); +      /* Check for _set or _get at the end of the name. */ +      if (Len(temp) > 4) { +	const char *p = Char(temp) + (Len(temp) - 4); +	if (strcmp(p, "_set") == 0) { +	  Delslice(temp, Len(temp) - 4, DOH_END); +	  Append(temp, "="); +	} else if (strcmp(p, "_get") == 0) { +	  Delslice(temp, Len(temp) - 4, DOH_END); +	} +      } +      if (multipleInheritance) { +	Printv(klass->init, tab4, "rb_define_method(", klass->mImpl, ", \"", temp, "\", ", wname, ", -1);\n", NIL); +      } else { +	Printv(klass->init, tab4, "rb_define_method(", klass->vname, ", \"", temp, "\", ", wname, ", -1);\n", NIL); +      } +      break; +    case STATIC_FUNC: +      Printv(klass->init, tab4, "rb_define_singleton_method(", klass->vname, ", \"", iname, "\", ", wname, ", -1);\n", NIL); +      break; +    case NO_CPP: +      if (!useGlobalModule) { +	Printv(s, tab4, "rb_define_module_function(", modvar, ", \"", iname, "\", ", wname, ", -1);\n", NIL); +	Printv(f_init, s, NIL); +      } else { +	Printv(s, tab4, "rb_define_global_function(\"", iname, "\", ", wname, ", -1);\n", NIL); +	Printv(f_init, s, NIL); +      } +      break; +    case DESTRUCTOR: +    case CLASS_CONST: +    case STATIC_VAR: +    default: +      assert(false);		// Should not have gotten here for these types +    } + +    defineAliases(n, iname); + +    Delete(temp); +    Delete(s); +    Delete(wname); +    Delete(alloc_func); +  } + +  /* --------------------------------------------------------------------- +   * applyInputTypemap() +   * +   * Look up the appropriate "in" typemap for this parameter (p), +   * substitute the correct strings for the typemap parameters, and dump the +   * resulting code to the wrapper file. +   * --------------------------------------------------------------------- */ + +  Parm *applyInputTypemap(Parm *p, String *source, Wrapper *f, String *symname) { +    String *tm; +    SwigType *pt = Getattr(p, "type"); +    if ((tm = Getattr(p, "tmap:in"))) { +      Replaceall(tm, "$input", source); +      Replaceall(tm, "$symname", symname); + +      if (Getattr(p, "wrap:disown") || (Getattr(p, "tmap:in:disown"))) { +	Replaceall(tm, "$disown", "SWIG_POINTER_DISOWN"); +      } else { +	Replaceall(tm, "$disown", "0"); +      } + +      Setattr(p, "emit:input", Copy(source)); +      Printf(f->code, "%s\n", tm); +      p = Getattr(p, "tmap:in:next"); +    } else { +      Swig_warning(WARN_TYPEMAP_IN_UNDEF, input_file, line_number, "Unable to use type %s as a function argument.\n", SwigType_str(pt, 0)); +      p = nextSibling(p); +    } +    return p; +  } + +  Parm *skipIgnoredArgs(Parm *p) { +    while (checkAttribute(p, "tmap:in:numinputs", "0")) { +      p = Getattr(p, "tmap:in:next"); +    } +    return p; +  } + +  /* --------------------------------------------------------------------- +   * marshalInputArgs() +   * +   * Process all of the arguments passed into the scripting language +   * method and convert them into C/C++ function arguments using the +   * supplied typemaps. +   * --------------------------------------------------------------------- */ + +  void marshalInputArgs(Node *n, ParmList *l, int numarg, int numreq, String *kwargs, bool allow_kwargs, Wrapper *f) { +    int i; +    Parm *p; +    String *tm; +    String *source; + +    source = NewString(""); + +    bool ctor_director = (current == CONSTRUCTOR_INITIALIZE && Swig_directorclass(n)); + +    /** +     * The 'start' value indicates which of the C/C++ function arguments +     * produced here corresponds to the first value in Ruby's argv[] array. +     * The value of start is either zero or one. If start is zero, then +     * the first argument (with name arg1) is based on the value of argv[0]. +     * If start is one, then arg1 is based on the value of argv[1]. +     */ +    int start = (current == MEMBER_FUNC || current == MEMBER_VAR || ctor_director) ? 1 : 0; + +    int varargs = emit_isvarargs(l); + +    Printf(kwargs, "{ "); +    for (i = 0, p = l; i < numarg; i++) { + +      p = skipIgnoredArgs(p); + +      String *pn = Getattr(p, "name"); + +      /* Produce string representation of source argument */ +      Clear(source); + +      /* First argument is a special case */ +      if (i == 0) { +	Printv(source, (start == 0) ? "argv[0]" : "self", NIL); +      } else { +	Printf(source, "argv[%d]", i - start); +      } + +      if (i >= (numreq)) {	/* Check if parsing an optional argument */ +	Printf(f->code, "    if (argc > %d) {\n", i - start); +      } + +      /* Record argument name for keyword argument handling */ +      if (Len(pn)) { +	Printf(kwargs, "\"%s\",", pn); +      } else { +	Printf(kwargs, "\"arg%d\",", i + 1); +      } + +      /* Look for an input typemap */ +      p = applyInputTypemap(p, source, f, Getattr(n, "name")); +      if (i >= numreq) { +	Printf(f->code, "}\n"); +      } +    } + +    /* Finish argument marshalling */ +    Printf(kwargs, " NULL }"); +    if (allow_kwargs) { +// kwarg support not implemented +//      Printv(f->locals, tab4, "const char *kwnames[] = ", kwargs, ";\n", NIL); +    } + +    /* Trailing varargs */ +    if (varargs) { +      if (p && (tm = Getattr(p, "tmap:in"))) { +	Clear(source); +	Printf(source, "argv[%d]", i - start); +	Replaceall(tm, "$input", source); +	Setattr(p, "emit:input", Copy(source)); +	Printf(f->code, "if (argc > %d) {\n", i - start); +	Printv(f->code, tm, "\n", NIL); +	Printf(f->code, "}\n"); +      } +    } + +    Delete(source); +  } + +  /* --------------------------------------------------------------------- +   * insertConstraintCheckingCode(ParmList *l, Wrapper *f) +   * +   * Checks each of the parameters in the parameter list for a "check" +   * typemap and (if it finds one) inserts the typemapping code into +   * the function wrapper. +   * --------------------------------------------------------------------- */ + +  void insertConstraintCheckingCode(ParmList *l, Wrapper *f) { +    Parm *p; +    String *tm; +    for (p = l; p;) { +      if ((tm = Getattr(p, "tmap:check"))) { +	Printv(f->code, tm, "\n", NIL); +	p = Getattr(p, "tmap:check:next"); +      } else { +	p = nextSibling(p); +      } +    } +  } + +  /* --------------------------------------------------------------------- +   * insertCleanupCode(ParmList *l, String *cleanup) +   * +   * Checks each of the parameters in the parameter list for a "freearg" +   * typemap and (if it finds one) inserts the typemapping code into +   * the function wrapper. +   * --------------------------------------------------------------------- */ + +  void insertCleanupCode(ParmList *l, String *cleanup) { +    String *tm; +    for (Parm *p = l; p;) { +      if ((tm = Getattr(p, "tmap:freearg"))) { +	if (Len(tm) != 0) { +	  Printv(cleanup, tm, "\n", NIL); +	} +	p = Getattr(p, "tmap:freearg:next"); +      } else { +	p = nextSibling(p); +      } +    } +  } + +  /* --------------------------------------------------------------------- +   * insertArgOutputCode(ParmList *l, String *outarg, int& need_result) +   * +   * Checks each of the parameters in the parameter list for a "argout" +   * typemap and (if it finds one) inserts the typemapping code into +   * the function wrapper. +   * --------------------------------------------------------------------- */ + +  void insertArgOutputCode(ParmList *l, String *outarg, int &need_result) { +    String *tm; +    for (Parm *p = l; p;) { +      if ((tm = Getattr(p, "tmap:argout"))) { +	Replaceall(tm, "$result", "vresult"); +	Replaceall(tm, "$arg", Getattr(p, "emit:input")); +	Replaceall(tm, "$input", Getattr(p, "emit:input")); + +	Printv(outarg, tm, "\n", NIL); +	need_result += 1; +	p = Getattr(p, "tmap:argout:next"); +      } else { +	p = nextSibling(p); +      } +    } +  } + +  /* --------------------------------------------------------------------- +   * validIdentifier() +   * +   * Is this a valid identifier in the scripting language? +   * Ruby method names can include any combination of letters, numbers +   * and underscores. A Ruby method name may optionally end with +   * a question mark ("?"), exclamation point ("!") or equals sign ("="). +   * +   * Methods whose names end with question marks are, by convention, +   * predicate methods that return true or false (e.g. Array#empty?). +   * +   * Methods whose names end with exclamation points are, by convention, +   * called bang methods that modify the instance in place (e.g. Array#sort!). +   * +   * Methods whose names end with an equals sign are attribute setters +   * (e.g. Thread#critical=). +   * --------------------------------------------------------------------- */ + +  virtual int validIdentifier(String *s) { +    char *c = Char(s); +    while (*c) { +      if (!(isalnum(*c) || (*c == '_') || (*c == '?') || (*c == '!') || (*c == '='))) +	return 0; +      c++; +    } +    return 1; +  } + +  /* --------------------------------------------------------------------- +   * functionWrapper() +   * +   * Create a function declaration and register it with the interpreter. +   * --------------------------------------------------------------------- */ + +  virtual int functionWrapper(Node *n) { + +    String *nodeType; +    bool destructor; + +    String *symname = Copy(Getattr(n, "sym:name")); +    SwigType *t = Getattr(n, "type"); +    ParmList *l = Getattr(n, "parms"); +    int director_method = 0; +    String *tm; + +    int need_result = 0; + +    /* Ruby needs no destructor wrapper */ +    if (current == DESTRUCTOR) +      return SWIG_NOWRAP; + +    nodeType = Getattr(n, "nodeType"); +    destructor = (!Cmp(nodeType, "destructor")); + +    /* If the C++ class constructor is overloaded, we only want to +     * write out the "new" singleton method once since it is always +     * the same. (It's the "initialize" method that will handle the +     * overloading). */ + +    if (current == CONSTRUCTOR_ALLOCATE && Swig_symbol_isoverloaded(n) && Getattr(n, "sym:nextSibling") != 0) +      return SWIG_OK; + +    String *overname = 0; +    if (Getattr(n, "sym:overloaded")) { +      overname = Getattr(n, "sym:overname"); +    } else { +      if (!addSymbol(symname, n)) +	return SWIG_ERROR; +    } + +    String *cleanup = NewString(""); +    String *outarg = NewString(""); +    String *kwargs = NewString(""); +    Wrapper *f = NewWrapper(); + +    /* Rename predicate methods */ +    if (GetFlag(n, "feature:predicate")) { +      Append(symname, "?"); +    } + +    /* Rename bang methods */ +    if (GetFlag(n, "feature:bang")) { +      Append(symname, "!"); +    } + +    /* Determine the name of the SWIG wrapper function */ +    String *wname = Swig_name_wrapper(symname); +    if (overname && current != CONSTRUCTOR_ALLOCATE) { +      Append(wname, overname); +    } + +    /* Emit arguments */ +    if (current != CONSTRUCTOR_ALLOCATE) { +      emit_parameter_variables(l, f); +    } + +    /* Attach standard typemaps */ +    if (current != CONSTRUCTOR_ALLOCATE) { +      emit_attach_parmmaps(l, f); +    } +    Setattr(n, "wrap:parms", l); + +    /* Get number of arguments */ +    int numarg = emit_num_arguments(l); +    int numreq = emit_num_required(l); +    int varargs = emit_isvarargs(l); +    bool allow_kwargs = GetFlag(n, "feature:kwargs") ? true : false; + +    bool ctor_director = (current == CONSTRUCTOR_INITIALIZE && Swig_directorclass(n)); +    int start = (current == MEMBER_FUNC || current == MEMBER_VAR || ctor_director) ? 1 : 0; + +    /* Now write the wrapper function itself */ +    if (current == CONSTRUCTOR_ALLOCATE) { +      Printv(f->def, "SWIGINTERN VALUE\n", NIL); +      Printf(f->def, "#ifdef HAVE_RB_DEFINE_ALLOC_FUNC\n"); +      Printv(f->def, wname, "(VALUE self)\n", NIL); +      Printf(f->def, "#else\n"); +      Printv(f->def, wname, "(int argc, VALUE *argv, VALUE self)\n", NIL); +      Printf(f->def, "#endif\n"); +      Printv(f->def, "{\n", NIL); +    } else if (current == CONSTRUCTOR_INITIALIZE) { +      Printv(f->def, "SWIGINTERN VALUE\n", wname, "(int argc, VALUE *argv, VALUE self) {", NIL); +      if (!varargs) { +	Printf(f->code, "if ((argc < %d) || (argc > %d)) ", numreq - start, numarg - start); +      } else { +	Printf(f->code, "if (argc < %d) ", numreq - start); +      } +      Printf(f->code, "{rb_raise(rb_eArgError, \"wrong # of arguments(%%d for %d)\",argc); SWIG_fail;}\n", numreq - start); +    } else { + +      if ( current == NO_CPP ) +	{ +	  String* docs = docstring(n, AUTODOC_FUNC); +	  Printf(f_wrappers, "%s", docs); +	  Delete(docs); +	} + +      Printv(f->def, "SWIGINTERN VALUE\n", wname, "(int argc, VALUE *argv, VALUE self) {", NIL); +      if (!varargs) { +	Printf(f->code, "if ((argc < %d) || (argc > %d)) ", numreq - start, numarg - start); +      } else { +	Printf(f->code, "if (argc < %d) ", numreq - start); +      } +      Printf(f->code, "{rb_raise(rb_eArgError, \"wrong # of arguments(%%d for %d)\",argc); SWIG_fail;}\n", numreq - start); +    } + +    /* Now walk the function parameter list and generate code */ +    /* to get arguments */ +    if (current != CONSTRUCTOR_ALLOCATE) { +      marshalInputArgs(n, l, numarg, numreq, kwargs, allow_kwargs, f); +    } +    // FIXME? +    if (ctor_director) { +      numarg--; +      numreq--; +    } + +    /* Insert constraint checking code */ +    insertConstraintCheckingCode(l, f); + +    /* Insert cleanup code */ +    insertCleanupCode(l, cleanup); + +    /* Insert argument output code */ +    insertArgOutputCode(l, outarg, need_result); + +    /* if the object is a director, and the method call originated from its +     * underlying Ruby object, resolve the call by going up the c++  +     * inheritance chain.  otherwise try to resolve the method in Ruby. +     * without this check an infinite loop is set up between the director and +     * shadow class method calls. +     */ + +    // NOTE: this code should only be inserted if this class is the +    // base class of a director class.  however, in general we haven't +    // yet analyzed all classes derived from this one to see if they are +    // directors.  furthermore, this class may be used as the base of +    // a director class defined in a completely different module at a +    // later time, so this test must be included whether or not directorbase +    // is true.  we do skip this code if directors have not been enabled +    // at the command line to preserve source-level compatibility with +    // non-polymorphic swig.  also, if this wrapper is for a smart-pointer +    // method, there is no need to perform the test since the calling object +    // (the smart-pointer) and the director object (the "pointee") are +    // distinct. + +    director_method = is_member_director(n) && !is_smart_pointer() && !destructor; +    if (director_method) { +      Wrapper_add_local(f, "director", "Swig::Director *director = 0"); +      Printf(f->code, "director = dynamic_cast<Swig::Director *>(arg1);\n"); +      Wrapper_add_local(f, "upcall", "bool upcall = false"); +      Append(f->code, "upcall = (director && (director->swig_get_self() == self));\n"); +    } + +    /* Now write code to make the function call */ +    if (current != CONSTRUCTOR_ALLOCATE) { +      if (current == CONSTRUCTOR_INITIALIZE) { +	Node *pn = Swig_methodclass(n); +	String *symname = Getattr(pn, "sym:name"); +	String *action = Getattr(n, "wrap:action"); +	if (directorsEnabled()) { +	  String *classname = NewStringf("const char *classname SWIGUNUSED = \"%s::%s\"", module, symname); +	  Wrapper_add_local(f, "classname", classname); +	} +	if (action) { +          SwigType *smart = Swig_cparse_smartptr(pn); +	  String *result_name = NewStringf("%s%s", smart ? "smart" : "", Swig_cresult_name()); +	  if (smart) { +	    String *result_var = NewStringf("%s *%s = 0", SwigType_namestr(smart), result_name); +	    Wrapper_add_local(f, result_name, result_var); +	    Printf(action, "\n%s = new %s(%s);", result_name, SwigType_namestr(smart), Swig_cresult_name()); +	  } +	  Printf(action, "\nDATA_PTR(self) = %s;", result_name); +	  if (GetFlag(pn, "feature:trackobjects")) { +	    Printf(action, "\nSWIG_RubyAddTracking(%s, self);", result_name); +	  } +	  Delete(result_name); +	  Delete(smart); +	} +      } + +      /* Emit the function call */ +      if (director_method) { +	Printf(f->code, "try {\n"); +      } + +      Setattr(n, "wrap:name", wname); + +      Swig_director_emit_dynamic_cast(n, f); +      String *actioncode = emit_action(n); + +      if (director_method) { +	Printf(actioncode, "} catch (Swig::DirectorException& e) {\n"); +	Printf(actioncode, "  rb_exc_raise(e.getError());\n"); +	Printf(actioncode, "  SWIG_fail;\n"); +	Printf(actioncode, "}\n"); +      } + +      /* Return value if necessary */ +      if (SwigType_type(t) != T_VOID && current != CONSTRUCTOR_INITIALIZE) { +        need_result = 1; +        if (GetFlag(n, "feature:predicate")) { +          Printv(actioncode, tab4, "vresult = (", Swig_cresult_name(), " ? Qtrue : Qfalse);\n", NIL); +        } else { +          tm = Swig_typemap_lookup_out("out", n, Swig_cresult_name(), f, actioncode); +          actioncode = 0; +          if (tm) { +            Replaceall(tm, "$result", "vresult"); + +            if (GetFlag(n, "feature:new")) +              Replaceall(tm, "$owner", "SWIG_POINTER_OWN"); +            else +              Replaceall(tm, "$owner", "0"); + +            // Unwrap return values that are director classes so that the original Ruby object is returned instead.  +            if (Swig_director_can_unwrap(n)) { +              Wrapper_add_local(f, "director", "Swig::Director *director = 0"); +              Printf(f->code, "director = dynamic_cast<Swig::Director *>(%s);\n", Swig_cresult_name()); +              Printf(f->code, "if (director) {\n"); +              Printf(f->code, "  vresult = director->swig_get_self();\n"); +              Printf(f->code, "} else {\n"); +              Printf(f->code, "%s\n", tm); +              Printf(f->code, "}\n"); +              director_method = 0; +            } else { +              Printf(f->code, "%s\n", tm); +            } + +            Delete(tm); +          } else { +            Swig_warning(WARN_TYPEMAP_OUT_UNDEF, input_file, line_number, "Unable to use return type %s.\n", SwigType_str(t, 0)); +          } +        } +      } +      if (actioncode) { +        Append(f->code, actioncode); +        Delete(actioncode); +      } +      emit_return_variable(n, t, f); +    } + +    /* Extra code needed for new and initialize methods */ +    if (current == CONSTRUCTOR_ALLOCATE) { +      Node *pn = Swig_methodclass(n); +      SwigType *smart = Swig_cparse_smartptr(pn); +      if (smart) +	SwigType_add_pointer(smart); +      String *classtype = smart ? smart : t; +      need_result = 1; +      Printf(f->code, "VALUE vresult = SWIG_NewClassInstance(self, SWIGTYPE%s);\n", Char(SwigType_manglestr(classtype))); +      Printf(f->code, "#ifndef HAVE_RB_DEFINE_ALLOC_FUNC\n"); +      Printf(f->code, "rb_obj_call_init(vresult, argc, argv);\n"); +      Printf(f->code, "#endif\n"); +      Delete(smart); +    } else if (current == CONSTRUCTOR_INITIALIZE) { +      need_result = 1; +    } +    else +      { +	if ( need_result > 1 ) { +	  if ( SwigType_type(t) == T_VOID ) +	    Printf(f->code, "vresult = rb_ary_new();\n"); +	  else +	    { +	      Printf(f->code, "if (vresult == Qnil) vresult = rb_ary_new();\n"); +	      Printf(f->code, "else vresult = SWIG_Ruby_AppendOutput( " +		     "rb_ary_new(), vresult);\n"); +	    } +	} +      } + +    /* Dump argument output code; */ +    Printv(f->code, outarg, NIL); + +    /* Dump the argument cleanup code */ +    int need_cleanup = (current != CONSTRUCTOR_ALLOCATE) && (Len(cleanup) != 0); +    if (need_cleanup) { +      Printv(f->code, cleanup, NIL); +    } + + +    /* Look for any remaining cleanup.  This processes the %new directive */ +    if (current != CONSTRUCTOR_ALLOCATE && GetFlag(n, "feature:new")) { +      tm = Swig_typemap_lookup("newfree", n, Swig_cresult_name(), 0); +      if (tm) { +	Printv(f->code, tm, "\n", NIL); +	Delete(tm); +      } +    } + +    /* Special processing on return value. */ +    tm = Swig_typemap_lookup("ret", n, Swig_cresult_name(), 0); +    if (tm) { +      Printv(f->code, tm, NIL); +      Delete(tm); +    } + +    if (director_method) { +      if ((tm = Swig_typemap_lookup("directorfree", n, Swig_cresult_name(), 0))) { +	Replaceall(tm, "$input", Swig_cresult_name()); +	Replaceall(tm, "$result", "vresult"); +	Printf(f->code, "%s\n", tm); +      } +    } + + +    /* Wrap things up (in a manner of speaking) */ +    if (need_result) { +      if (current == CONSTRUCTOR_ALLOCATE) { +	Printv(f->code, tab4, "return vresult;\n", NIL); +      } else if (current == CONSTRUCTOR_INITIALIZE) { +	Printv(f->code, tab4, "return self;\n", NIL); +	Printv(f->code, "fail:\n", NIL); +	if (need_cleanup) { +	  Printv(f->code, cleanup, NIL); +	} +	Printv(f->code, tab4, "return Qnil;\n", NIL); +      } else { +	Wrapper_add_local(f, "vresult", "VALUE vresult = Qnil"); +	Printv(f->code, tab4, "return vresult;\n", NIL); +	Printv(f->code, "fail:\n", NIL); +	if (need_cleanup) { +	  Printv(f->code, cleanup, NIL); +	} +	Printv(f->code, tab4, "return Qnil;\n", NIL); +      } +    } else { +      Printv(f->code, tab4, "return Qnil;\n", NIL); +      Printv(f->code, "fail:\n", NIL); +      if (need_cleanup) { +	Printv(f->code, cleanup, NIL); +      } +      Printv(f->code, tab4, "return Qnil;\n", NIL); +    } + +    Printf(f->code, "}\n"); + +    /* Substitute the cleanup code */ +    Replaceall(f->code, "$cleanup", cleanup); + +    /* Substitute the function name */ +    Replaceall(f->code, "$symname", symname); + +    /* Emit the function */ +    Wrapper_print(f, f_wrappers); + +    /* Now register the function with the interpreter */ +    if (!Swig_symbol_isoverloaded(n)) { +      create_command(n, symname); +    } else { +      if (current == CONSTRUCTOR_ALLOCATE) { +	create_command(n, symname); +      } else { +	if (!Getattr(n, "sym:nextSibling")) +	  dispatchFunction(n); +      } +    } + +    Delete(kwargs); +    Delete(cleanup); +    Delete(outarg); +    DelWrapper(f); +    Delete(symname); + +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * dispatchFunction() +   * ------------------------------------------------------------ */ + +  void dispatchFunction(Node *n) { +    /* Last node in overloaded chain */ + +    int maxargs; +    String *tmp = NewString(""); +    String *dispatch = Swig_overload_dispatch(n, "return %s(nargs, args, self);", &maxargs); + +    /* Generate a dispatch wrapper for all overloaded functions */ + +    Wrapper *f = NewWrapper(); +    String *symname = Getattr(n, "sym:name"); +    String *wname = Swig_name_wrapper(symname); + +    Printv(f->def, "SWIGINTERN VALUE ", wname, "(int nargs, VALUE *args, VALUE self) {", NIL); + +    Wrapper_add_local(f, "argc", "int argc"); +    bool ctor_director = (current == CONSTRUCTOR_INITIALIZE && Swig_directorclass(n)); +    if (current == MEMBER_FUNC || current == MEMBER_VAR || ctor_director) { +      Printf(tmp, "VALUE argv[%d]", maxargs + 1); +    } else { +      Printf(tmp, "VALUE argv[%d]", maxargs); +    } +    Wrapper_add_local(f, "argv", tmp); +    Wrapper_add_local(f, "ii", "int ii"); + +    if (current == MEMBER_FUNC || current == MEMBER_VAR || ctor_director) { +      maxargs += 1; +      Printf(f->code, "argc = nargs + 1;\n"); +      Printf(f->code, "argv[0] = self;\n"); +      Printf(f->code, "if (argc > %d) SWIG_fail;\n", maxargs); +      Printf(f->code, "for (ii = 1; (ii < argc); ++ii) {\n"); +      Printf(f->code, "argv[ii] = args[ii-1];\n"); +      Printf(f->code, "}\n"); +    } else { +      Printf(f->code, "argc = nargs;\n"); +      Printf(f->code, "if (argc > %d) SWIG_fail;\n", maxargs); +      Printf(f->code, "for (ii = 0; (ii < argc); ++ii) {\n"); +      Printf(f->code, "argv[ii] = args[ii];\n"); +      Printf(f->code, "}\n"); +    } + +    Replaceall(dispatch, "$args", "nargs, args, self"); +    Printv(f->code, dispatch, "\n", NIL); + + +     +    // Generate prototype list, go to first node +    Node *sibl = n; + +    while (Getattr(sibl, "sym:previousSibling")) +      sibl = Getattr(sibl, "sym:previousSibling");	// go all the way up + +    // Constructors will be treated specially +    const bool isCtor = (!Cmp(Getattr(sibl, "nodeType"), "constructor")); +    const bool isMethod = ( Cmp(Getattr(sibl, "ismember"), "1") == 0 && +			    (!isCtor) ); + +    // Construct real method name +    String* methodName = NewString(""); +    if ( isMethod ) { +      // Sometimes a method node has no parent (SF#3034054). +      // This value is used in an exception message, so just skip the class +      // name in this case so at least we don't segfault.  This is probably +      // just working around a problem elsewhere though. +      Node *parent_node = parentNode(sibl); +      if (parent_node) +	Printv( methodName, Getattr(parent_node,"sym:name"), ".", NIL ); +    } +    Append( methodName, Getattr(sibl,"sym:name" ) ); +    if ( isCtor ) Append( methodName, ".new" );  + +    // Generate prototype list +    String *protoTypes = NewString(""); +    do { +      Append( protoTypes, "\n\"    "); +      if (!isCtor) { +	SwigType *type = SwigType_str(Getattr(sibl, "type"), NULL); +	Printv(protoTypes, type, " ", NIL); +	Delete(type); +      } +      Printv(protoTypes, methodName, NIL ); +      Parm* p = Getattr(sibl, "wrap:parms"); +      if (p && (current == MEMBER_FUNC || current == MEMBER_VAR ||  +		ctor_director) ) +	p = nextSibling(p); // skip self +      Append( protoTypes, "(" ); +      while(p) +	{ + 	  Append( protoTypes, SwigType_str(Getattr(p,"type"), Getattr(p,"name")) ); +	  if ( ( p = nextSibling(p)) ) Append(protoTypes, ", "); +	} +      Append( protoTypes, ")\\n\"" ); +    } while ((sibl = Getattr(sibl, "sym:nextSibling"))); + +    Append(f->code, "fail:\n"); +    Printf(f->code, "Ruby_Format_OverloadedError( argc, %d, \"%s\", %s);\n",  +	   maxargs, methodName, protoTypes); +    Append(f->code, "\nreturn Qnil;\n"); + +    Delete(methodName); +    Delete(protoTypes); + +    Printv(f->code, "}\n", NIL); +    Wrapper_print(f, f_wrappers); +    create_command(n, Char(symname)); + +    DelWrapper(f); +    Delete(dispatch); +    Delete(tmp); +    Delete(wname); +  } + +  /* --------------------------------------------------------------------- +   * variableWrapper() +   * --------------------------------------------------------------------- */ + +  virtual int variableWrapper(Node *n) { +    String* docs = docstring(n, AUTODOC_GETTER); +    Printf(f_wrappers, "%s", docs); +    Delete(docs); + + +    char *name = GetChar(n, "name"); +    char *iname = GetChar(n, "sym:name"); +    SwigType *t = Getattr(n, "type"); +    String *tm; +    String *getfname, *setfname; +    Wrapper *getf, *setf; +    const int assignable = is_assignable(n); + +    // Determine whether virtual global variables shall be used +    // which have different getter and setter signatures, +    // see https://docs.ruby-lang.org/en/2.6.0/extension_rdoc.html#label-Global+Variables+Shared+Between+C+and+Ruby +    const bool use_virtual_var = (current == NO_CPP && useGlobalModule); + +    getf = NewWrapper(); +    setf = NewWrapper(); + +    /* create getter */ +    int addfail = 0; +    String *getname = Swig_name_get(NSPACE_TODO, iname); +    getfname = Swig_name_wrapper(getname); +    Setattr(n, "wrap:name", getfname); +    Printv(getf->def, "SWIGINTERN VALUE\n", getfname, "(", NIL); +    Printf(getf->def, (use_virtual_var) ? "ID id, VALUE *data" : "VALUE self"); +    Printf(getf->def, ") {"); +    Wrapper_add_local(getf, "_val", "VALUE _val"); + +    tm = Swig_typemap_lookup("varout", n, name, 0); +    if (tm) { +      Replaceall(tm, "$result", "_val"); +      /* Printv(getf->code,tm, NIL); */ +      addfail = emit_action_code(n, getf->code, tm); +    } else { +      Swig_warning(WARN_TYPEMAP_VAROUT_UNDEF, input_file, line_number, "Unable to read variable of type %s\n", SwigType_str(t, 0)); +    } +    Printv(getf->code, tab4, "return _val;\n", NIL); +    if (addfail) { +      Append(getf->code, "fail:\n"); +      Append(getf->code, "  return Qnil;\n"); +    } +    Append(getf->code, "}\n"); + +    Wrapper_print(getf, f_wrappers); + +    if (!assignable) { +      setfname = NewString("(rb_gvar_setter_t *)NULL"); +    } else { +      /* create setter */ +      String* docs = docstring(n, AUTODOC_SETTER); +      Printf(f_wrappers, "%s", docs); +      Delete(docs); + +      String *setname = Swig_name_set(NSPACE_TODO, iname); +      setfname = Swig_name_wrapper(setname); +      Setattr(n, "wrap:name", setfname); +      Printf(setf->def, "SWIGINTERN "); +      if (use_virtual_var) { +        Printv(setf->def, "void\n", setfname, "(VALUE _val, ID id, VALUE *data) {", NIL); +      } else { +        Printv(setf->def, "VALUE\n", setfname, "(VALUE self, VALUE _val) {", NIL); +      } +      tm = Swig_typemap_lookup("varin", n, name, 0); +      if (tm) { +	Replaceall(tm, "$input", "_val"); +	/* Printv(setf->code,tm,"\n",NIL); */ +	emit_action_code(n, setf->code, tm); +      } else { +	Swig_warning(WARN_TYPEMAP_VARIN_UNDEF, input_file, line_number, "Unable to set variable of type %s\n", SwigType_str(t, 0)); +      } +      if (use_virtual_var) { +        Printf(setf->code, "fail:\n"); +        Printv(setf->code, tab4, "return;\n", NIL); +      } else { +        Printv(setf->code, tab4, "return _val;\n", NIL); +        Printf(setf->code, "fail:\n"); +        Printv(setf->code, tab4, "return Qnil;\n", NIL); +      } +      Printf(setf->code, "}\n"); +      Wrapper_print(setf, f_wrappers); +      Delete(setname); +    } + +    /* define accessor methods */ +    Insert(getfname, 0, "VALUEFUNC("); +    Append(getfname, ")"); +    Insert(setfname, 0, (use_virtual_var) ? "SWIG_RUBY_VOID_ANYARGS_FUNC(" : "VALUEFUNC("); +    Append(setfname, ")"); + +    String *s = NewString(""); +    switch (current) { +    case STATIC_VAR: +      /* C++ class variable */ +      Printv(s, tab4, "rb_define_singleton_method(", klass->vname, ", \"", klass->strip(iname), "\", ", getfname, ", 0);\n", NIL); +      if (assignable) { +	Printv(s, tab4, "rb_define_singleton_method(", klass->vname, ", \"", klass->strip(iname), "=\", ", setfname, ", 1);\n", NIL); +      } +      Printv(klass->init, s, NIL); +      break; +    default: +      /* C global variable */ +      /* wrapped in Ruby module attribute */ +      assert(current == NO_CPP); +      if (!useGlobalModule) { +	Printv(s, tab4, "rb_define_singleton_method(", modvar, ", \"", iname, "\", ", getfname, ", 0);\n", NIL); +	if (assignable) { +	  Printv(s, tab4, "rb_define_singleton_method(", modvar, ", \"", iname, "=\", ", setfname, ", 1);\n", NIL); +	} +      } else { +	Printv(s, tab4, "rb_define_virtual_variable(\"$", iname, "\", ", getfname, ", ", setfname, ");\n", NIL); +      } +      Printv(f_init, s, NIL); +      Delete(s); +      break; +    } +    Delete(getname); +    Delete(getfname); +    Delete(setfname); +    DelWrapper(setf); +    DelWrapper(getf); +    return SWIG_OK; +  } + + +  /* --------------------------------------------------------------------- +   * validate_const_name(char *name) +   * +   * Validate constant name. +   * --------------------------------------------------------------------- */ + +  char *validate_const_name(char *name, const char *reason) { +    if (!name || name[0] == '\0') +      return name; + +    if (isupper(name[0])) +      return name; + +    if (islower(name[0])) { +      name[0] = (char)toupper(name[0]); +      Swig_warning(WARN_RUBY_WRONG_NAME, input_file, line_number, "Wrong %s name (corrected to `%s')\n", reason, name); +      return name; +    } + +    Swig_warning(WARN_RUBY_WRONG_NAME, input_file, line_number, "Wrong %s name %s\n", reason, name); + +    return name; +  } + +  /* --------------------------------------------------------------------- +   * constantWrapper() +   * --------------------------------------------------------------------- */ + +  virtual int constantWrapper(Node *n) { +    Swig_require("constantWrapper", n, "*sym:name", "type", "value", NIL); + +    char *iname = GetChar(n, "sym:name"); +    SwigType *type = Getattr(n, "type"); +    String *rawval = Getattr(n, "rawval"); +    String *value = rawval ? rawval : Getattr(n, "value"); + +    if (current == CLASS_CONST) { +      iname = klass->strip(iname); +    } +    validate_const_name(iname, "constant"); +    SetChar(n, "sym:name", iname); + +    /* Special hook for member pointer */ +    if (SwigType_type(type) == T_MPOINTER) { +      String *wname = Swig_name_wrapper(iname); +      Printf(f_header, "static %s = %s;\n", SwigType_str(type, wname), value); +      value = Char(wname); +    } +    String *tm = Swig_typemap_lookup("constant", n, value, 0); +    if (!tm) +      tm = Swig_typemap_lookup("constcode", n, value, 0); +    if (tm) { +      Replaceall(tm, "$symname", iname); +      Replaceall(tm, "$value", value); +      if (current == CLASS_CONST) { +	if (multipleInheritance) { +	  Replaceall(tm, "$module", klass->mImpl); +	  Printv(klass->init, tm, "\n", NIL); +	} else { +	  Replaceall(tm, "$module", klass->vname); +	  Printv(klass->init, tm, "\n", NIL); +	} +      } else { +	if (!useGlobalModule) { +	  Replaceall(tm, "$module", modvar); +	} else { +	  Replaceall(tm, "$module", "rb_cObject"); +	} +	Printf(f_init, "%s\n", tm); +      } +    } else { +      Swig_warning(WARN_TYPEMAP_CONST_UNDEF, input_file, line_number, "Unsupported constant value %s = %s\n", SwigType_str(type, 0), value); +    } +    Swig_restore(n); +    return SWIG_OK; +  } + +  /* ----------------------------------------------------------------------------- +   * classDeclaration()  +   * +   * Records information about classes---even classes that might be defined in +   * other modules referenced by %import. +   * ----------------------------------------------------------------------------- */ + +  virtual int classDeclaration(Node *n) { +    if (!Getattr(n, "feature:onlychildren")) { +      String *name = Getattr(n, "name"); +      String *symname = Getattr(n, "sym:name"); + +      String *namestr = SwigType_namestr(name); +      klass = RCLASS(classes, Char(namestr)); +      if (!klass) { +	klass = new RClass(); +	String *valid_name = NewString(symname ? symname : namestr); +	validate_const_name(Char(valid_name), "class"); +	klass->set_name(namestr, symname, valid_name); +	SET_RCLASS(classes, Char(namestr), klass); +	Delete(valid_name); +      } +      Delete(namestr); +    } +    return Language::classDeclaration(n); +  } + +  /** +   * Process the comma-separated list of mixed-in module names (if any). +   */ +  void includeRubyModules(Node *n) { +    String *mixin = Getattr(n, "feature:mixin"); +    if (mixin) { +      List *modules = Split(mixin, ',', INT_MAX); +      if (modules && Len(modules) > 0) { +	Iterator mod = First(modules); +	while (mod.item) { +	  if (Len(mod.item) > 0) { +	    Printf(klass->init, "rb_include_module(%s, rb_eval_string(\"%s\"));\n", klass->vname, mod.item); +	  } +	  mod = Next(mod); +	} +      } +      Delete(modules); +    } +  } + +  void handleBaseClasses(Node *n) { +    List *baselist = Getattr(n, "bases"); +    if (baselist && Len(baselist)) { +      Iterator base = First(baselist); +      while (base.item && GetFlag(base.item, "feature:ignore")) { +	base = Next(base); +      } +      while (base.item) { +	String *basename = Getattr(base.item, "name"); +	String *basenamestr = SwigType_namestr(basename); +	RClass *super = RCLASS(classes, Char(basenamestr)); +	Delete(basenamestr); +	if (super) { +	  SwigType *btype = NewString(basename); +	  SwigType_add_pointer(btype); +	  SwigType_remember(btype); +	  SwigType *smart = Swig_cparse_smartptr(base.item); +	  if (smart) { +	    SwigType_add_pointer(smart); +	    SwigType_remember(smart); +	  } +	  String *bmangle = SwigType_manglestr(smart ? smart : btype); +	  if (multipleInheritance) { +	    Insert(bmangle, 0, "((swig_class *) SWIGTYPE"); +	    Append(bmangle, "->clientdata)->mImpl"); +	    Printv(klass->init, "rb_include_module(", klass->mImpl, ", ", bmangle, ");\n", NIL); +	  } else { +	    Insert(bmangle, 0, "((swig_class *) SWIGTYPE"); +	    Append(bmangle, "->clientdata)->klass"); +	    Replaceall(klass->init, "$super", bmangle); +	  } +	  Delete(bmangle); +	  Delete(smart); +	  Delete(btype); +	} +	base = Next(base); +	while (base.item && GetFlag(base.item, "feature:ignore")) { +	  base = Next(base); +	} +	if (!multipleInheritance) { +	  /* Warn about multiple inheritance for additional base class(es) */ +	  while (base.item) { +	    if (GetFlag(base.item, "feature:ignore")) { +	      base = Next(base); +	      continue; +	    } +	    String *proxyclassname = SwigType_str(Getattr(n, "classtypeobj"), 0); +	    String *baseclassname = SwigType_str(Getattr(base.item, "name"), 0); +	    Swig_warning(WARN_RUBY_MULTIPLE_INHERITANCE, Getfile(n), Getline(n), +			 "Warning for %s, base %s ignored. Multiple inheritance is not supported in Ruby.\n", proxyclassname, baseclassname); +	    base = Next(base); +	  } +	} +      } +    } +  } + +  /** +   * Check to see if a %markfunc was specified. +   */ +  void handleMarkFuncDirective(Node *n) { +    String *markfunc = Getattr(n, "feature:markfunc"); +    if (markfunc) { +      Printf(klass->init, "SwigClass%s.mark = (void (*)(void *)) %s;\n", klass->name, markfunc); +    } else { +      Printf(klass->init, "SwigClass%s.mark = 0;\n", klass->name); +    } +  } + +  /** +   * Check to see if a %freefunc was specified. +   */ +  void handleFreeFuncDirective(Node *n) { +    String *freefunc = Getattr(n, "feature:freefunc"); +    if (freefunc) { +      Printf(klass->init, "SwigClass%s.destroy = (void (*)(void *)) %s;\n", klass->name, freefunc); +    } else { +      if (klass->destructor_defined) { +	Printf(klass->init, "SwigClass%s.destroy = (void (*)(void *)) free_%s;\n", klass->name, klass->mname); +      } +    } +  } + +  /** +   * Check to see if tracking is enabled for this class. +   */ +  void handleTrackDirective(Node *n) { +    int trackObjects = GetFlag(n, "feature:trackobjects"); +    if (trackObjects) { +      Printf(klass->init, "SwigClass%s.trackObjects = 1;\n", klass->name); +    } else { +      Printf(klass->init, "SwigClass%s.trackObjects = 0;\n", klass->name); +    } +  } + +  /* ---------------------------------------------------------------------- +   * classHandler() +   * ---------------------------------------------------------------------- */ + +  virtual int classHandler(Node *n) { +    String* docs = docstring(n, AUTODOC_CLASS); +    Printf(f_wrappers, "%s", docs); +    Delete(docs); + +    String *name = Getattr(n, "name"); +    String *symname = Getattr(n, "sym:name"); +    String *namestr = SwigType_namestr(name);	// does template expansion + +    klass = RCLASS(classes, Char(namestr)); +    assert(klass != 0); +    Delete(namestr); +    String *valid_name = NewString(symname); +    validate_const_name(Char(valid_name), "class"); + +    Clear(klass->type); +    Printv(klass->type, Getattr(n, "classtype"), NIL); +    Printv(f_wrappers, "static swig_class SwigClass", valid_name, ";\n\n", NIL); +    Printv(klass->init, "\n", tab4, NIL); + +    if (!useGlobalModule) { +      Printv(klass->init, klass->vname, " = rb_define_class_under(", modvar, ", \"", klass->name, "\", $super);\n", NIL); +    } else { +      Printv(klass->init, klass->vname, " = rb_define_class(\"", klass->name,  +	     "\", $super);\n", NIL); +    } + +    if (multipleInheritance) { +      Printv(klass->init, klass->mImpl, " = rb_define_module_under(", klass->vname, ", \"Impl\");\n", NIL); +    } + +    SwigType *tt = NewString(name); +    SwigType_add_pointer(tt); +    SwigType_remember(tt); +    SwigType *smart = Swig_cparse_smartptr(n); +    if (smart) { +      SwigType_add_pointer(smart); +      SwigType_remember(smart); +    } +    String *tm = SwigType_manglestr(smart ? smart : tt); +    Printf(klass->init, "SWIG_TypeClientData(SWIGTYPE%s, (void *) &SwigClass%s);\n", tm, valid_name); +    Delete(tm); +    Delete(smart); +    Delete(tt); +    Delete(valid_name); + +    includeRubyModules(n); + +    Printv(klass->init, "$allocator", NIL); +    Printv(klass->init, "$initializer", NIL); + +    Language::classHandler(n); + +    handleBaseClasses(n); +    handleMarkFuncDirective(n); +    handleFreeFuncDirective(n); +    handleTrackDirective(n); + +    if (multipleInheritance) { +      Printv(klass->init, "rb_include_module(", klass->vname, ", ", klass->mImpl, ");\n", NIL); +    } + +    String *s = NewString(""); +    Printv(s, tab4, "rb_undef_alloc_func(", klass->vname, ");\n", NIL); +    Replaceall(klass->init, "$allocator", s); +    Replaceall(klass->init, "$initializer", ""); + +    if (GetFlag(n, "feature:exceptionclass")) { +      Replaceall(klass->init, "$super", "rb_eRuntimeError"); +    } else { +      Replaceall(klass->init, "$super", "rb_cObject"); +    } +    Delete(s); + +    Printv(f_init, klass->init, NIL); +    klass = 0; +    return SWIG_OK; +  } + +  /* ---------------------------------------------------------------------- +   * memberfunctionHandler() +   * +   * Method for adding C++ member function +   * +   * By default, we're going to create a function of the form : +   * +   *         Foo_bar(this,args) +   * +   * Where Foo is the classname, bar is the member name and the this pointer +   * is explicitly attached to the beginning. +   * +   * The renaming only applies to the member function part, not the full +   * classname. +   * +   * --------------------------------------------------------------------- */ + +  virtual int memberfunctionHandler(Node *n) { +    current = MEMBER_FUNC; + +    String* docs = docstring(n, AUTODOC_METHOD); +    Printf(f_wrappers, "%s", docs); +    Delete(docs); + +    Language::memberfunctionHandler(n); +    current = NO_CPP; +    return SWIG_OK; +  } + +  /* --------------------------------------------------------------------- +   * constructorHandler() +   * +   * Method for adding C++ member constructor +   * -------------------------------------------------------------------- */ + +  void set_director_ctor_code(Node *n) { +    /* director ctor code is specific for each class */ +    Delete(director_prot_ctor_code); +    director_prot_ctor_code = NewString(""); +    Node *pn = Swig_methodclass(n); +    String *symname = Getattr(pn, "sym:name"); +    String *name = Copy(symname); +    char *cname = Char(name); +    if (cname) +      cname[0] = (char)toupper(cname[0]); +    Printv(director_prot_ctor_code, +	   "if ( $comparison ) { /* subclassed */\n", +	   "  $director_new \n", +	   "} else {\n", "  rb_raise(rb_eNameError,\"accessing abstract class or protected constructor\"); \n", "  return Qnil;\n", "}\n", NIL); +    Delete(director_ctor_code); +    director_ctor_code = NewString(""); +    Printv(director_ctor_code, "if ( $comparison ) { /* subclassed */\n", "  $director_new \n", "} else {\n", "  $nondirector_new \n", "}\n", NIL); +    Delete(name); +  } + +  virtual int constructorHandler(Node *n) { +    int use_director = Swig_directorclass(n); +    if (use_director) { +      set_director_ctor_code(n); +    } + +    /* First wrap the allocate method */ +    current = CONSTRUCTOR_ALLOCATE; +    Swig_name_register("construct", "%n%c_allocate"); + +    Language::constructorHandler(n); + +    String* docs = docstring(n, AUTODOC_CTOR); +    Printf(f_wrappers, "%s", docs); +    Delete(docs); + +    /*  +     * If we're wrapping the constructor of a C++ director class, prepend a new parameter +     * to receive the scripting language object (e.g. 'self') +     * +     */ +    Swig_save("ruby:constructorHandler", n, "parms", NIL); +    if (use_director) { +      Parm *parms = Getattr(n, "parms"); +      Parm *self; +      String *name = NewString("self"); +      String *type = NewString("VALUE"); +      self = NewParm(type, name, n); +      Delete(type); +      Delete(name); +      Setattr(self, "lname", "Qnil"); +      if (parms) +	set_nextSibling(self, parms); +      Setattr(n, "parms", self); +      Setattr(n, "wrap:self", "1"); +      Delete(self); +    } + +    /* Now do the instance initialize method */ +    current = CONSTRUCTOR_INITIALIZE; +    Swig_name_register("construct", "new_%n%c"); +    Language::constructorHandler(n); + +    /* Restore original parameter list */ +    Delattr(n, "wrap:self"); +    Swig_restore(n); + +    /* Done */ +    Swig_name_unregister("construct"); +    current = NO_CPP; +    klass->constructor_defined = 1; +    return SWIG_OK; +  } + +  virtual int copyconstructorHandler(Node *n) { +    int use_director = Swig_directorclass(n); +    if (use_director) { +      set_director_ctor_code(n); +    } + +    /* First wrap the allocate method */ +    current = CONSTRUCTOR_ALLOCATE; +    Swig_name_register("construct", "%n%c_allocate"); + +    return Language::copyconstructorHandler(n); +  } + + +  /* --------------------------------------------------------------------- +   * destructorHandler() +   * -------------------------------------------------------------------- */ + +  virtual int destructorHandler(Node *n) { + +    /* Do no spit free function if user defined his own for this class */ +    Node *pn = Swig_methodclass(n); +    String *freefunc = Getattr(pn, "feature:freefunc"); +    if (freefunc) return SWIG_OK; + +    current = DESTRUCTOR; +    Language::destructorHandler(n); + +    freefunc = NewString(""); +    String *freebody = NewString(""); +    String *pname0 = Swig_cparm_name(0, 0); + +    Printv(freefunc, "free_", klass->mname, NIL); +    Printv(freebody, "SWIGINTERN void\n", freefunc, "(void *self) {\n", NIL); +    Printv(freebody, tab4, klass->type, " *", pname0, " = (", klass->type, " *)self;\n", NIL); +    Printv(freebody, tab4, NIL); + +    /* Check to see if object tracking is activated for the class +       that owns this destructor. */ +    if (GetFlag(pn, "feature:trackobjects")) { +      Printf(freebody, "SWIG_RubyRemoveTracking(%s);\n", pname0); +      Printv(freebody, tab4, NIL); +    } + +    if (Extend) { +      String *wrap = Getattr(n, "wrap:code"); +      if (wrap) { +	Printv(f_wrappers, wrap, NIL); +      } +      /*    Printv(freebody, Swig_name_destroy(name), "(", pname0, ")", NIL); */ +      Printv(freebody, Getattr(n, "wrap:action"), "\n", NIL); +    } else { +      String *action = Getattr(n, "wrap:action"); +      if (action) { +	Printv(freebody, action, "\n", NIL); +      } else { +	/* In the case swig emits no destroy function. */ +	if (CPlusPlus) +	  Printf(freebody, "delete %s;\n", pname0); +	else +	  Printf(freebody, "free((char*) %s);\n", pname0); +      } +    } + +    Printv(freebody, "}\n\n", NIL); + +    Printv(f_wrappers, freebody, NIL); + +    klass->destructor_defined = 1; +    current = NO_CPP; +    Delete(freefunc); +    Delete(freebody); +    Delete(pname0); +    return SWIG_OK; +  } + +  /* --------------------------------------------------------------------- +   * membervariableHandler() +   * +   * This creates a pair of functions to set/get the variable of a member. +   * -------------------------------------------------------------------- */ + +  virtual int membervariableHandler(Node *n) { +    String* docs = docstring(n, AUTODOC_GETTER); +    Printf(f_wrappers, "%s", docs); +    Delete(docs); + +    if (is_assignable(n)) { +      String* docs = docstring(n, AUTODOC_SETTER); +      Printf(f_wrappers, "%s", docs); +      Delete(docs); +    } + +    current = MEMBER_VAR; +    Language::membervariableHandler(n); +    current = NO_CPP; +    return SWIG_OK; +  } + +  /* ----------------------------------------------------------------------- +   * staticmemberfunctionHandler() +   * +   * Wrap a static C++ function +   * ---------------------------------------------------------------------- */ + +  virtual int staticmemberfunctionHandler(Node *n) { +    String* docs = docstring(n, AUTODOC_STATICFUNC); +    Printf(f_wrappers, "%s", docs); +    Delete(docs); + +    current = STATIC_FUNC; +    Language::staticmemberfunctionHandler(n); +    current = NO_CPP; +    return SWIG_OK; +  } + +  /* ---------------------------------------------------------------------- +   * memberconstantHandler() +   * +   * Create a C++ constant +   * --------------------------------------------------------------------- */ + +  virtual int memberconstantHandler(Node *n) { +    String* docs = docstring(n, AUTODOC_STATICFUNC); +    Printf(f_wrappers, "%s", docs); +    Delete(docs); + +    current = CLASS_CONST; +    Language::memberconstantHandler(n); +    current = NO_CPP; +    return SWIG_OK; +  } + +  /* --------------------------------------------------------------------- +   * staticmembervariableHandler() +   * --------------------------------------------------------------------- */ + +  virtual int staticmembervariableHandler(Node *n) { +    String* docs = docstring(n, AUTODOC_GETTER); +    Printf(f_wrappers, "%s", docs); +    Delete(docs); + +    if (is_assignable(n)) { +      String* docs = docstring(n, AUTODOC_SETTER); +      Printf(f_wrappers, "%s", docs); +      Delete(docs); +    } + +    current = STATIC_VAR; +    Language::staticmembervariableHandler(n); +    current = NO_CPP; +    return SWIG_OK; +  } + +  /* C++ director class generation */ +  virtual int classDirector(Node *n) { +    return Language::classDirector(n); +  } + +  virtual int classDirectorInit(Node *n) { +    String *declaration; +    declaration = Swig_director_declaration(n); +    Printf(f_directors_h, "\n"); +    Printf(f_directors_h, "%s\n", declaration); +    Printf(f_directors_h, "public:\n"); +    Delete(declaration); +    return Language::classDirectorInit(n); +  } + +  virtual int classDirectorEnd(Node *n) { +    Printf(f_directors_h, "};\n\n"); +    return Language::classDirectorEnd(n); +  } + +  /* ------------------------------------------------------------ +   * classDirectorConstructor() +   * ------------------------------------------------------------ */ + +  virtual int classDirectorConstructor(Node *n) { +    Node *parent = Getattr(n, "parentNode"); +    String *sub = NewString(""); +    String *decl = Getattr(n, "decl"); +    String *supername = Swig_class_name(parent); +    String *classname = NewString(""); +    Printf(classname, "SwigDirector_%s", supername); + +    /* insert self parameter */ +    Parm *p; +    ParmList *superparms = Getattr(n, "parms"); +    ParmList *parms = CopyParmList(superparms); +    String *type = NewString("VALUE"); +    p = NewParm(type, NewString("self"), n); +    set_nextSibling(p, parms); +    parms = p; + +    if (!Getattr(n, "defaultargs")) { +      /* constructor */ +      { +	Wrapper *w = NewWrapper(); +	String *call; +	String *basetype = Getattr(parent, "classtype"); +	String *target = Swig_method_decl(0, decl, classname, parms, 0); +	call = Swig_csuperclass_call(0, basetype, superparms); +	Printf(w->def, "%s::%s: %s, Swig::Director(self) { }", classname, target, call); +	Delete(target); +	Wrapper_print(w, f_directors); +	Delete(call); +	DelWrapper(w); +      } + +      /* constructor header */ +      { +	String *target = Swig_method_decl(0, decl, classname, parms, 1); +	Printf(f_directors_h, "    %s;\n", target); +	Delete(target); +      } +    } + +    Delete(sub); +    Delete(classname); +    Delete(supername); +    Delete(parms); +    return Language::classDirectorConstructor(n); +  } + +  /* ------------------------------------------------------------ +   * classDirectorDefaultConstructor() +   * ------------------------------------------------------------ */ + +  virtual int classDirectorDefaultConstructor(Node *n) { +    String *classname; +    Wrapper *w; +    classname = Swig_class_name(n); +    w = NewWrapper(); +    Printf(w->def, "SwigDirector_%s::SwigDirector_%s(VALUE self) : Swig::Director(self) { }", classname, classname); +    Wrapper_print(w, f_directors); +    DelWrapper(w); +    Printf(f_directors_h, "    SwigDirector_%s(VALUE self);\n", classname); +    Delete(classname); +    return Language::classDirectorDefaultConstructor(n); +  } + +  /* --------------------------------------------------------------- +   * exceptionSafeMethodCall() +   * +   * Emit a virtual director method to pass a method call on to the  +   * underlying Ruby instance. +   * +   * --------------------------------------------------------------- */ + +  void exceptionSafeMethodCall(String *className, Node *n, Wrapper *w, int argc, String *args, bool initstack) { +    Wrapper *body = NewWrapper(); +    Wrapper *rescue = NewWrapper(); + +    String *methodName = Getattr(n, "sym:name"); + +    String *bodyName = NewStringf("%s_%s_body", className, methodName); +    String *rescueName = NewStringf("%s_%s_rescue", className, methodName); +    String *depthCountName = NewStringf("%s_%s_call_depth", className, methodName); + +    // Check for an exception typemap of some kind +    String *tm = Swig_typemap_lookup("director:except", n, Swig_cresult_name(), 0); +    if (!tm) { +      tm = Getattr(n, "feature:director:except"); +    } + +    if ((tm != 0) && (Len(tm) > 0) && (Strcmp(tm, "1") != 0)) { +      // Declare a global to hold the depth count +      if (!Getattr(n, "sym:nextSibling")) { +	Printf(body->def, "static int %s = 0;\n", depthCountName); + +	// Function body +	Printf(body->def, "VALUE %s(VALUE data) {\n", bodyName); +	Wrapper_add_localv(body, "args", "Swig::body_args *", "args", "= reinterpret_cast<Swig::body_args *>(data)", NIL); +	Wrapper_add_localv(body, Swig_cresult_name(), "VALUE", Swig_cresult_name(), "= Qnil", NIL); +	Printf(body->code, "%s++;\n", depthCountName); +	Printv(body->code, Swig_cresult_name(), " = rb_funcall2(args->recv, args->id, args->argc, args->argv);\n", NIL); +	Printf(body->code, "%s--;\n", depthCountName); +	Printv(body->code, "return ", Swig_cresult_name(), ";\n", NIL); +	Printv(body->code, "}", NIL); + +	// Exception handler +	Printf(rescue->def, "VALUE %s(VALUE args, VALUE error) {\n", rescueName); +	Replaceall(tm, "$error", "error"); +	Printf(rescue->code, "%s--;\n", depthCountName); +	Printf(rescue->code, "if (%s == 0) ", depthCountName); +	Printv(rescue->code, Str(tm), "\n", NIL); +	Printv(rescue->code, "rb_exc_raise(error);\n", NIL); +	Printv(rescue->code, "return Qnil;\n", NIL); +	Printv(rescue->code, "}", NIL); +      } + +      // Main code +      Wrapper_add_localv(w, "args", "Swig::body_args", "args", NIL); +      Wrapper_add_localv(w, "status", "int", "status", NIL); +      Printv(w->code, "args.recv = swig_get_self();\n", NIL); +      Printf(w->code, "args.id = rb_intern(\"%s\");\n", methodName); +      Printf(w->code, "args.argc = %d;\n", argc); +      if (argc > 0) { +	Printf(w->code, "args.argv = new VALUE[%d];\n", argc); +	for (int i = 0; i < argc; i++) { +	  Printf(w->code, "args.argv[%d] = obj%d;\n", i, i); +	} +      } else { +	Printv(w->code, "args.argv = 0;\n", NIL); +      } +      Printf(w->code, "%s = rb_protect(PROTECTFUNC(%s), reinterpret_cast<VALUE>(&args), &status);\n", Swig_cresult_name(), bodyName); +      if ( initstack ) Printf(w->code, "SWIG_RELEASE_STACK;\n"); +      Printf(w->code, "if (status) {\n"); +      Printf(w->code, "VALUE lastErr = rb_gv_get(\"$!\");\n"); +      Printf(w->code, "%s(reinterpret_cast<VALUE>(&args), lastErr);\n", rescueName); +      Printf(w->code, "}\n"); +      if (argc > 0) { +	Printv(w->code, "delete [] args.argv;\n", NIL); +      } +      // Dump wrapper code +      Wrapper_print(body, f_directors_helpers); +      Wrapper_print(rescue, f_directors_helpers); +    } else { +      if (argc > 0) { +	Printf(w->code, "%s = rb_funcall(swig_get_self(), rb_intern(\"%s\"), %d%s);\n", Swig_cresult_name(), methodName, argc, args); +      } else { +	Printf(w->code, "%s = rb_funcall(swig_get_self(), rb_intern(\"%s\"), 0, Qnil);\n", Swig_cresult_name(), methodName); +      } +      if ( initstack ) Printf(w->code, "SWIG_RELEASE_STACK;\n"); +    } + +    // Clean up +    Delete(bodyName); +    Delete(rescueName); +    Delete(depthCountName); +    DelWrapper(body); +    DelWrapper(rescue); +  } + +  virtual int classDirectorMethod(Node *n, Node *parent, String *super) { +    int is_void = 0; +    int is_pointer = 0; +    String *decl = Getattr(n, "decl"); +    String *name = Getattr(n, "name"); +    String *classname = Getattr(parent, "sym:name"); +    String *c_classname = Getattr(parent, "name"); +    String *symname = Getattr(n, "sym:name"); +    String *declaration = NewString(""); +    ParmList *l = Getattr(n, "parms"); +    Wrapper *w = NewWrapper(); +    String *tm; +    String *wrap_args = NewString(""); +    String *returntype = Getattr(n, "type"); +    Parm *p; +    String *value = Getattr(n, "value"); +    String *storage = Getattr(n, "storage"); +    bool pure_virtual = false; +    int status = SWIG_OK; +    int idx; +    bool ignored_method = GetFlag(n, "feature:ignore") ? true : false; +    bool asvoid = checkAttribute( n, "feature:numoutputs", "0") ? true : false; +    bool initstack = checkAttribute( n, "feature:initstack", "1") ? true : false; + +    if (Cmp(storage, "virtual") == 0) { +      if (Cmp(value, "0") == 0) { +	pure_virtual = true; +      } +    } +    String *overnametmp = NewString(Getattr(n, "sym:name")); +    if (Getattr(n, "sym:overloaded")) { +      Printf(overnametmp, "::%s", Getattr(n, "sym:overname")); +    } + +    /* determine if the method returns a pointer */ +    is_pointer = SwigType_ispointer_return(decl); +    is_void = (!Cmp(returntype, "void") && !is_pointer); + +    /* virtual method definition */ +    String *target; +    String *pclassname = NewStringf("SwigDirector_%s", classname); +    String *qualified_name = NewStringf("%s::%s", pclassname, name); +    SwigType *rtype = Getattr(n, "conversion_operator") ? 0 : Getattr(n, "classDirectorMethods:type"); +    target = Swig_method_decl(rtype, decl, qualified_name, l, 0); +    Printf(w->def, "%s", target); +    Delete(qualified_name); +    Delete(target); +    /* header declaration */ +    target = Swig_method_decl(rtype, decl, name, l, 1); +    Printf(declaration, "    virtual %s", target); +    Delete(target); + +    // Get any exception classes in the throws typemap +    if (Getattr(n, "noexcept")) { +      Append(w->def, " noexcept"); +      Append(declaration, " noexcept"); +    } +    ParmList *throw_parm_list = 0; + +    if ((throw_parm_list = Getattr(n, "throws")) || Getattr(n, "throw")) { +      Parm *p; +      int gencomma = 0; + +      Append(w->def, " throw("); +      Append(declaration, " throw("); + +      if (throw_parm_list) +	Swig_typemap_attach_parms("throws", throw_parm_list, 0); +      for (p = throw_parm_list; p; p = nextSibling(p)) { +	if (Getattr(p, "tmap:throws")) { +	  if (gencomma++) { +	    Append(w->def, ", "); +	    Append(declaration, ", "); +	  } + +	  Printf(w->def, "%s", SwigType_str(Getattr(p, "type"), 0)); +	  Printf(declaration, "%s", SwigType_str(Getattr(p, "type"), 0)); +	} +      } + +      Append(w->def, ")"); +      Append(declaration, ")"); +    } + +    Append(w->def, " {"); +    Append(declaration, ";\n"); + +    if (initstack && !(ignored_method && !pure_virtual)) { +      Append(w->def, "\nSWIG_INIT_STACK;\n"); +    } + +    /* declare method return value  +     * if the return value is a reference or const reference, a specialized typemap must +     * handle it, including declaration of c_result ($result). +     */ +    if (!is_void && (!ignored_method || pure_virtual)) { +      if (!SwigType_isclass(returntype)) { +	if (!(SwigType_ispointer(returntype) || SwigType_isreference(returntype))) { +	  String *construct_result = NewStringf("= SwigValueInit< %s >()", SwigType_lstr(returntype, 0)); +	  Wrapper_add_localv(w, "c_result", SwigType_lstr(returntype, "c_result"), construct_result, NIL); +	  Delete(construct_result); +	} else { +	  Wrapper_add_localv(w, "c_result", SwigType_lstr(returntype, "c_result"), "= 0", NIL); +	} +      } else { +	String *cres = SwigType_lstr(returntype, "c_result"); +	Printf(w->code, "%s;\n", cres); +	Delete(cres); +      } +    } + +    if (ignored_method) { +      if (!pure_virtual) { +	if (!is_void) +	  Printf(w->code, "return "); +	String *super_call = Swig_method_call(super, l); +	Printf(w->code, "%s;\n", super_call); +	Delete(super_call); +      } else { +	Printf(w->code, "Swig::DirectorPureVirtualException::raise(\"Attempted to invoke pure virtual method %s::%s\");\n", SwigType_namestr(c_classname), +	       SwigType_namestr(name)); +      } +    } else { +      /* attach typemaps to arguments (C/C++ -> Ruby) */ +      String *arglist = NewString(""); + +      Swig_director_parms_fixup(l); + +      Swig_typemap_attach_parms("in", l, 0); +      Swig_typemap_attach_parms("directorin", l, w); +      Swig_typemap_attach_parms("directorargout", l, w); + +      char source[256]; + +      int outputs = 0; +      if (!is_void && !asvoid) +	outputs++; + +      /* build argument list and type conversion string */ +      idx = 0; p = l; +      while ( p ) { + +	if (Getattr(p, "tmap:ignore")) { +	  p = Getattr(p, "tmap:ignore:next"); +	  continue; +	} + +	if (Getattr(p, "tmap:directorargout") != 0) +	  outputs++; + +	if ( checkAttribute( p, "tmap:in:numinputs", "0") ) { +	  p = Getattr(p, "tmap:in:next"); +	  continue; +	} + +	String *parameterName = Getattr(p, "name"); +	String *parameterType = Getattr(p, "type"); + +	Putc(',', arglist); +	if ((tm = Getattr(p, "tmap:directorin")) != 0) { +	  sprintf(source, "obj%d", idx++); +	  String *input = NewString(source); +	  Setattr(p, "emit:directorinput", input); +	  Replaceall(tm, "$input", input); +	  Replaceall(tm, "$owner", "0"); +	  Delete(input); +	  Printv(wrap_args, tm, "\n", NIL); +	  Wrapper_add_localv(w, source, "VALUE", source, "= Qnil", NIL); +	  Printv(arglist, source, NIL); +	  p = Getattr(p, "tmap:directorin:next"); +	  continue; +	} else if (Cmp(parameterType, "void")) { +	  /** +	   * Special handling for pointers to other C++ director classes. +	   * Ideally this would be left to a typemap, but there is currently no +	   * way to selectively apply the dynamic_cast<> to classes that have +	   * directors.  In other words, the type "SwigDirector_$1_lname" only exists +	   * for classes with directors.  We avoid the problem here by checking +	   * module.wrap::directormap, but it's not clear how to get a typemap to +	   * do something similar.  Perhaps a new default typemap (in addition +	   * to SWIGTYPE) called DIRECTORTYPE? +	   */ +	  if (SwigType_ispointer(parameterType) || SwigType_isreference(parameterType)) { +	    Node *modname = Getattr(parent, "module"); +	    Node *target = Swig_directormap(modname, parameterType); +	    sprintf(source, "obj%d", idx++); +	    String *nonconst = 0; +	    /* strip pointer/reference --- should move to Swig/stype.c */ +	    String *nptype = NewString(Char(parameterType) + 2); +	    /* name as pointer */ +	    String *ppname = Copy(parameterName); +	    if (SwigType_isreference(parameterType)) { +	      Insert(ppname, 0, "&"); +	    } +	    /* if necessary, cast away const since Ruby doesn't support it! */ +	    if (SwigType_isconst(nptype)) { +	      nonconst = NewStringf("nc_tmp_%s", parameterName); +	      String *nonconst_i = NewStringf("= const_cast< %s >(%s)", SwigType_lstr(parameterType, 0), ppname); +	      Wrapper_add_localv(w, nonconst, SwigType_lstr(parameterType, 0), nonconst, nonconst_i, NIL); +	      Delete(nonconst_i); +	      Swig_warning(WARN_LANG_DISCARD_CONST, input_file, line_number, +			   "Target language argument '%s' discards const in director method %s::%s.\n", SwigType_str(parameterType, parameterName), +			   SwigType_namestr(c_classname), SwigType_namestr(name)); +	    } else { +	      nonconst = Copy(ppname); +	    } +	    Delete(nptype); +	    Delete(ppname); +	    String *mangle = SwigType_manglestr(parameterType); +	    if (target) { +	      String *director = NewStringf("director_%s", mangle); +	      Wrapper_add_localv(w, director, "Swig::Director *", director, "= 0", NIL); +	      Wrapper_add_localv(w, source, "VALUE", source, "= Qnil", NIL); +	      Printf(wrap_args, "%s = dynamic_cast<Swig::Director *>(%s);\n", director, nonconst); +	      Printf(wrap_args, "if (!%s) {\n", director); +	      Printf(wrap_args, "%s = SWIG_NewPointerObj(%s, SWIGTYPE%s, 0);\n", source, nonconst, mangle); +	      Printf(wrap_args, "} else {\n"); +	      Printf(wrap_args, "%s = %s->swig_get_self();\n", source, director); +	      Printf(wrap_args, "}\n"); +	      Delete(director); +	      Printv(arglist, source, NIL); +	    } else { +	      Wrapper_add_localv(w, source, "VALUE", source, "= Qnil", NIL); +	      Printf(wrap_args, "%s = SWIG_NewPointerObj(%s, SWIGTYPE%s, 0);\n", source, nonconst, mangle); +	      //Printf(wrap_args, "%s = SWIG_NewPointerObj(%s, SWIGTYPE_p_%s, 0);\n",  +	      //       source, nonconst, base); +	      Printv(arglist, source, NIL); +	    } +	    Delete(mangle); +	    Delete(nonconst); +	  } else { +	    Swig_warning(WARN_TYPEMAP_DIRECTORIN_UNDEF, input_file, line_number, +			 "Unable to use type %s as a function argument in director method %s::%s (skipping method).\n", SwigType_str(parameterType, 0), +			 SwigType_namestr(c_classname), SwigType_namestr(name)); +	    status = SWIG_NOWRAP; +	    break; +	  } +	} +	p = nextSibling(p); +      } + +      /* declare Ruby return value */ +      String *value_result = NewStringf("VALUE SWIGUNUSED %s", Swig_cresult_name()); +      Wrapper_add_local(w, Swig_cresult_name(), value_result); +      Delete(value_result); + +      /* wrap complex arguments to VALUEs */ +      Printv(w->code, wrap_args, NIL); + +      /* pass the method call on to the Ruby object */ +      exceptionSafeMethodCall(classname, n, w, idx, arglist, initstack); + +      /* +       * Ruby method may return a simple object, or an Array of objects. +       * For in/out arguments, we have to extract the appropriate VALUEs from the Array, +       * then marshal everything back to C/C++ (return value and output arguments). +       */ + +      /* Marshal return value and other outputs (if any) from VALUE to C/C++ type */ + +      String *cleanup = NewString(""); +      String *outarg = NewString(""); + +      if (outputs > 1) { +	Wrapper_add_local(w, "output", "VALUE output"); +	Printf(w->code, "if (TYPE(%s) != T_ARRAY) {\n", Swig_cresult_name()); +	Printf(w->code, "Ruby_DirectorTypeMismatchException(\"Ruby method failed to return an array.\");\n"); +	Printf(w->code, "}\n"); +      } + +      idx = 0; + +      /* Marshal return value */ +      if (!is_void) { +	tm = Swig_typemap_lookup("directorout", n, Swig_cresult_name(), w); +	if (tm != 0) { +	  if (outputs > 1 && !asvoid ) { +	    Printf(w->code, "output = rb_ary_entry(%s, %d);\n", Swig_cresult_name(), idx++); +	    Replaceall(tm, "$input", "output"); +	  } else { +	    Replaceall(tm, "$input", Swig_cresult_name()); +	  } +	  /* TODO check this */ +	  if (Getattr(n, "wrap:disown")) { +	    Replaceall(tm, "$disown", "SWIG_POINTER_DISOWN"); +	  } else { +	    Replaceall(tm, "$disown", "0"); +	  } +	  Replaceall(tm, "$result", "c_result"); +	  Printv(w->code, tm, "\n", NIL); +	} else { +	  Swig_warning(WARN_TYPEMAP_DIRECTOROUT_UNDEF, input_file, line_number, +		       "Unable to use return type %s in director method %s::%s (skipping method).\n", SwigType_str(returntype, 0), +		       SwigType_namestr(c_classname), SwigType_namestr(name)); +	  status = SWIG_ERROR; +	} +      } + +      /* Marshal outputs */ +      for (p = l; p;) { +	if ((tm = Getattr(p, "tmap:directorargout")) != 0) { +	  if (outputs > 1) { +	    Printf(w->code, "output = rb_ary_entry(%s, %d);\n", Swig_cresult_name(), idx++); +	    Replaceall(tm, "$result", "output"); +	  } else { +	    Replaceall(tm, "$result", Swig_cresult_name()); +	  } +	  Replaceall(tm, "$input", Getattr(p, "emit:directorinput")); +	  Printv(w->code, tm, "\n", NIL); +	  p = Getattr(p, "tmap:directorargout:next"); +	} else { +	  p = nextSibling(p); +	} +      } + +      Delete(arglist); +      Delete(cleanup); +      Delete(outarg); +    } + +    /* any existing helper functions to handle this? */ +    if (!is_void) { +      if (!(ignored_method && !pure_virtual)) { +	String *rettype = SwigType_str(returntype, 0); +	if (!SwigType_isreference(returntype)) { +	  Printf(w->code, "return (%s) c_result;\n", rettype); +	} else { +	  Printf(w->code, "return (%s) *c_result;\n", rettype); +	} +	Delete(rettype); +      } +    } + +    Printf(w->code, "}\n"); + +    // We expose protected methods via an extra public inline method which makes a straight call to the wrapped class' method +    String *inline_extra_method = NewString(""); +    if (dirprot_mode() && !is_public(n) && !pure_virtual) { +      Printv(inline_extra_method, declaration, NIL); +      String *extra_method_name = NewStringf("%sSwigPublic", name); +      Replaceall(inline_extra_method, name, extra_method_name); +      Replaceall(inline_extra_method, ";\n", " {\n      "); +      if (!is_void) +	Printf(inline_extra_method, "return "); +      String *methodcall = Swig_method_call(super, l); +      Printv(inline_extra_method, methodcall, ";\n    }\n", NIL); +      Delete(methodcall); +      Delete(extra_method_name); +    } + +    /* emit the director method */ +    if (status == SWIG_OK) { +      if (!Getattr(n, "defaultargs")) { +	Replaceall(w->code, "$symname", symname); +	Wrapper_print(w, f_directors); +	Printv(f_directors_h, declaration, NIL); +	Printv(f_directors_h, inline_extra_method, NIL); +      } +    } + +    /* clean up */ +    Delete(wrap_args); +    Delete(pclassname); +    DelWrapper(w); +    return status; +  } + +  virtual int classDirectorConstructors(Node *n) { +    return Language::classDirectorConstructors(n); +  } + +  virtual int classDirectorMethods(Node *n) { +    return Language::classDirectorMethods(n); +  } + +  virtual int classDirectorDisown(Node *n) { +    return Language::classDirectorDisown(n); +  } + +  String *runtimeCode() { +    String *s = NewString(""); +    String *shead = Swig_include_sys("rubyhead.swg"); +    if (!shead) { +      Printf(stderr, "*** Unable to open 'rubyhead.swg'\n"); +    } else { +      Append(s, shead); +      Delete(shead); +    } +    String *serrors = Swig_include_sys("rubyerrors.swg"); +    if (!serrors) { +      Printf(stderr, "*** Unable to open 'rubyerrors.swg'\n"); +    } else { +      Append(s, serrors); +      Delete(serrors); +    } +    String *strack = Swig_include_sys("rubytracking.swg"); +    if (!strack) { +      Printf(stderr, "*** Unable to open 'rubytracking.swg'\n"); +    } else { +      Append(s, strack); +      Delete(strack); +    } +    String *sapi = Swig_include_sys("rubyapi.swg"); +    if (!sapi) { +      Printf(stderr, "*** Unable to open 'rubyapi.swg'\n"); +    } else { +      Append(s, sapi); +      Delete(sapi); +    } +    String *srun = Swig_include_sys("rubyrun.swg"); +    if (!srun) { +      Printf(stderr, "*** Unable to open 'rubyrun.swg'\n"); +    } else { +      Append(s, srun); +      Delete(srun); +    } +    return s; +  } + +  String *defaultExternalRuntimeFilename() { +    return NewString("swigrubyrun.h"); +  } + +  /*---------------------------------------------------------------------- +   * kwargsSupport() +   *--------------------------------------------------------------------*/ + +  bool kwargsSupport() const { +    // kwargs support isn't actually implemented, but changing to return false may break something now as it turns on compactdefaultargs +    return true; +  } +};				/* class RUBY */ + +/* ----------------------------------------------------------------------------- + * swig_ruby()    - Instantiate module + * ----------------------------------------------------------------------------- */ + +static Language *new_swig_ruby() { +  return new RUBY(); +} +extern "C" Language *swig_ruby(void) { +  return new_swig_ruby(); +} + + +/* + * Local Variables: + * c-basic-offset: 2 + * End: + */ diff --git a/contrib/tools/swig/Source/Modules/scilab.cxx b/contrib/tools/swig/Source/Modules/scilab.cxx new file mode 100644 index 00000000000..aabd2d84260 --- /dev/null +++ b/contrib/tools/swig/Source/Modules/scilab.cxx @@ -0,0 +1,1167 @@ +/* ---------------------------------------------------------------------------- + * This file is part of SWIG, which is licensed as a whole under version 3 + * (or any later version) of the GNU General Public License. Some additional + * terms also apply to certain portions of SWIG. The full details of the SWIG + * license and copyrights can be found in the LICENSE and COPYRIGHT files + * included with the SWIG source code as distributed by the SWIG developers + * and at https://www.swig.org/legal.html. + * + * scilab.cxx + * + * Scilab language module for SWIG. + * --------------------------------------------------------------------------*/ + +#include "swigmod.h" +#include <cstddef> +#include <cstdlib> + +static const int SCILAB_IDENTIFIER_NAME_CHAR_MAX = 24; + +static const char *usage = (char *) " \ +Scilab options (available with -scilab)\n \ +     -builder                               - Generate a Scilab builder script\n \ +     -buildercflags <cflags>                - Add <cflags> to the builder compiler flags\n \ +     -builderflagscript <file>              - Set the Scilab script <file> to use by builder to configure the build flags\n \ +     -builderldflags <ldflags>              - Add <ldflags> to the builder linker flags\n \ +     -buildersources <files>                - Add the (comma separated) files <files> to the builder sources\n \ +     -builderverbositylevel <level>         - Set the builder verbosity level to <level> (default 0: off, 2: high)\n \ +     -gatewayxml <gateway_id>               - Generate gateway xml with the given <gateway_id>\n \ +\n"; + + +class SCILAB:public Language { +protected: +  /* General objects used for holding the strings */ +  File *beginSection; +  File *runtimeSection; +  File *headerSection; +  File *wrappersSection; +  File *initSection; + +  String *variablesCode; + +  bool generateBuilder; +  File *builderFile; +  String *builderCode; +  String *builderCode5; +  String *builderCode6; +  int builderFunctionCount; + +  List *sourceFileList; +  List *cflags; +  List *ldflags; + +  String *verboseBuildLevel; +  String *buildFlagsScript; + +  String *gatewayHeader; +  String *gatewayHeaderV5; +  String *gatewayHeaderV6; + +  bool createGatewayXML; +  File *gatewayXMLFile; +  String *gatewayXML; +  String *gatewayID; +  int primitiveID; + +  bool createLoader; +  File *loaderFile; +  String *loaderScript; +  String *loaderScript5; +  String *loaderScript6; +  int loaderFunctionCount; +public: + +  /* ------------------------------------------------------------------------ +   * main() +   * ----------------------------------------------------------------------*/ + +  virtual void main(int argc, char *argv[]) { +    generateBuilder = false; +    sourceFileList = NewList(); +    cflags = NewList(); +    ldflags = NewList(); +    verboseBuildLevel = NULL; +    buildFlagsScript = NULL; + +    gatewayHeader = NULL; +    gatewayHeaderV5 = NULL; +    gatewayHeaderV6 = NULL; + +    createGatewayXML = false; +    gatewayXML = NULL; +    gatewayXMLFile = NULL; +    gatewayID = NULL; + +    createLoader = true; +    loaderFile = NULL; +    loaderScript = NULL; + +    /* Manage command line arguments */ +    for (int argIndex = 1; argIndex < argc; argIndex++) { +      if (argv[argIndex] != NULL) { +	if (strcmp(argv[argIndex], "-help") == 0) { +	  Printf(stdout, "%s\n", usage); +	} else if (strcmp(argv[argIndex], "-builder") == 0) { +	  Swig_mark_arg(argIndex); +	  generateBuilder = true; +	  createLoader = false; +	} else if (strcmp(argv[argIndex], "-buildersources") == 0) { +	  if (argv[argIndex + 1] != NULL) { +	    Swig_mark_arg(argIndex); +	    char *sourceFile = strtok(argv[argIndex + 1], ","); +	    while (sourceFile != NULL) { +	      Insert(sourceFileList, Len(sourceFileList), sourceFile); +	      sourceFile = strtok(NULL, ","); +	    } +	    Swig_mark_arg(argIndex + 1); +	  } +	} else if (strcmp(argv[argIndex], "-buildercflags") == 0) { +          Swig_mark_arg(argIndex); +          if (argv[argIndex + 1] != NULL) { +            Insert(cflags, Len(cflags), argv[argIndex + 1]); +            Swig_mark_arg(argIndex + 1); +          } +        } else if (strcmp(argv[argIndex], "-builderldflags") == 0) { +          Swig_mark_arg(argIndex); +          if (argv[argIndex + 1] != NULL) { +            Insert(ldflags, Len(ldflags), argv[argIndex + 1]); +            Swig_mark_arg(argIndex + 1); +          } +        } else if (strcmp(argv[argIndex], "-builderverbositylevel") == 0) { +          Swig_mark_arg(argIndex); +          verboseBuildLevel = NewString(argv[argIndex + 1]); +          Swig_mark_arg(argIndex + 1); +        } else if (strcmp(argv[argIndex], "-builderflagscript") == 0) { +          Swig_mark_arg(argIndex); +          buildFlagsScript = NewString(argv[argIndex + 1]); +          Swig_mark_arg(argIndex + 1); +        } else if (strcmp(argv[argIndex], "-gatewayxml") == 0) { +          Swig_mark_arg(argIndex); +          createGatewayXML = true; +          gatewayID = NewString(argv[argIndex + 1]); +          Swig_mark_arg(argIndex + 1); +        } +      } +    } + +    if (verboseBuildLevel == NULL) { +      verboseBuildLevel = NewString("0"); +    } + +    /* Set language-specific subdirectory in SWIG library */ +    SWIG_library_directory("scilab"); + +    /* Add a symbol to the parser for conditional compilation */ +    Preprocessor_define("SWIGSCILAB 1", 0); + +    /* Set scilab configuration file */ +    SWIG_config_file("scilab.swg"); + +    /* Set typemap for scilab */ +    SWIG_typemap_lang("scilab"); + +    allow_overloading(); +  } + +  /* ------------------------------------------------------------------------ +   * top() +   * ----------------------------------------------------------------------*/ + +  virtual int top(Node *node) { + +    /* Get the module name */ +    String *gatewayName = Getattr(node, "name"); + +    // Set library name +    String *gatewayLibraryName = NewStringf("lib%s", gatewayName); + +    /* Get the output file name */ +    String *outputFilename = Getattr(node, "outfile"); + +    /* Initialize I/O */ +    beginSection = NewFile(outputFilename, "w", SWIG_output_files()); +    if (!beginSection) { +      FileErrorDisplay(outputFilename); +      Exit(EXIT_FAILURE); +    } +    runtimeSection = NewString(""); +    initSection = NewString(""); +    headerSection = NewString(""); +    wrappersSection = NewString(""); + +    /* Register file targets with the SWIG file handler */ +    Swig_register_filebyname("begin", beginSection); +    Swig_register_filebyname("header", headerSection); +    Swig_register_filebyname("wrapper", wrappersSection); +    Swig_register_filebyname("runtime", runtimeSection); +    Swig_register_filebyname("init", initSection); + +    /* Output module initialization code */ +    Swig_banner(beginSection); + +    Swig_obligatory_macros(runtimeSection, "SCILAB"); + +    // Gateway header source merged with wrapper source in nobuilder mode +    if (!generateBuilder) +      startGatewayHeader(gatewayLibraryName); + +    // Create builder file if required +    if (generateBuilder) { +      createBuilderFile(outputFilename); +    } + +    // Create gateway XML if required +    if (createGatewayXML) { +      createGatewayXMLFile(gatewayName); +    } + +    // Create loader script if required +    if (createLoader) { +      createLoaderFile(gatewayLibraryName); +    } + +    // Module initialization function +    String *smallFunctionName = createSmallIdentifierName(gatewayName, SCILAB_IDENTIFIER_NAME_CHAR_MAX - 5); +    String *gatewayInitFunctionName = NewStringf("%s_Init", gatewayName); +    String *gatewayInitSmallFunctionName = NewStringf("%s_Init", smallFunctionName); +    String *wrapperFunctionName = NewStringf("SWIG_%s_Init", gatewayName); + +    /* Add initialization function to builder table */ +    addFunctionToScilab(gatewayInitFunctionName, gatewayInitSmallFunctionName, wrapperFunctionName); + +    // Add helper functions to builder table +    addHelperFunctions(); + +    // Open Scilab wrapper variables creation function +    variablesCode = NewString(""); +    Printf(variablesCode, "int SWIG_CreateScilabVariables(void *_pvApiCtx) {"); + +    /* Emit code for children */ +    if (CPlusPlus) { +      Printf(wrappersSection, "extern \"C\" {\n"); +    } + +    Language::top(node); + +    if (CPlusPlus) { +      Printf(wrappersSection, "}\n"); +    } +    // Close Scilab wrapper variables creation function +    Printf(variablesCode, "  return SWIG_OK;\n}\n"); + +    // Add Builder footer code and save +    if (generateBuilder) { +      saveBuilderFile(gatewayLibraryName); +    } + +    /* Close the init function and rename with module name */ +    Printf(initSection, "return 0;\n}\n"); +    Replaceall(initSection, "<module>", gatewayName); + +    /* Write all to the wrapper file */ +    SwigType_emit_type_table(runtimeSection, wrappersSection);	// Declare pointer types, ... (Ex: SWIGTYPE_p_p_double) + +    // Gateway header source merged with wrapper source in nobuilder mode +    if (!generateBuilder) { +      terminateGatewayHeader(gatewayLibraryName); +      Printv(initSection, gatewayHeader, NIL); +    } + +    Dump(runtimeSection, beginSection); +    Dump(headerSection, beginSection); +    Dump(wrappersSection, beginSection); +    Dump(variablesCode, beginSection); +    Wrapper_pretty_print(initSection, beginSection); + +    if (createGatewayXML) { +      saveGatewayXMLFile(); +    } + +    if (createLoader) { +      saveLoaderFile(gatewayLibraryName); +    } + +    /* Cleanup files */ +    Delete(runtimeSection); +    Delete(headerSection); +    Delete(wrappersSection); +    Delete(initSection); +    Delete(beginSection); + +    Delete(sourceFileList); +    Delete(cflags); +    Delete(ldflags); + +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------------------ +   * emitBanner() +   * ----------------------------------------------------------------------*/ + +  void emitBanner(File *f) { +    Printf(f, "// ----------------------------------------------------------------------------\n"); +    Swig_banner_target_lang(f, "// "); +    Printf(f, "// ----------------------------------------------------------------------------- */\n\n"); +  } + +  /* ------------------------------------------------------------------------ +   * functionWrapper() +   * ----------------------------------------------------------------------*/ + +  virtual int functionWrapper(Node *node) { + +    /* Get some useful attributes of this function */ +    String *functionName = Getattr(node, "sym:name"); +    String *smallFunctionName = createSmallIdentifierName(functionName); + +    SwigType *functionReturnType = Getattr(node, "type"); +    ParmList *functionParamsList = Getattr(node, "parms"); + +    int paramIndex = 0;		// Used for loops over ParmsList +    Parm *param = NULL;		// Used for loops over ParamsList + +    /* Create the wrapper object */ +    Wrapper *wrapper = NewWrapper(); + +    /* Create the function wrapper name */ +    String *wrapperName = Swig_name_wrapper(functionName); + +    /* Deal with overloading */ +    String *overloadedName = Copy(wrapperName); +    /* Determine whether the function is overloaded or not */ +    bool isOverloaded = ! !Getattr(node, "sym:overloaded"); +    /* Determine whether the function is the last overloaded */ +    bool isLastOverloaded = isOverloaded && !Getattr(node, "sym:nextSibling"); + +    if (!isOverloaded && !addSymbol(functionName, node)) { +      DelWrapper(wrapper); +      return SWIG_ERROR; +    } + +    if (isOverloaded) { +      Append(overloadedName, Getattr(node, "sym:overname")); +    } + +    /* Write the wrapper function definition (standard Scilab gateway function prototype) */ +    Printv(wrapper->def, "SWIGEXPORT int ", overloadedName, "(SWIG_GatewayParameters) {", NIL); + +    /* Emit all of the local variables for holding arguments */ +    // E.g.: double arg1; +    emit_parameter_variables(functionParamsList, wrapper); + +    /* Attach typemaps to the parameter list */ +    // Add local variables used in typemaps (iRows, iCols, ...) +    emit_attach_parmmaps(functionParamsList, wrapper); +    Setattr(node, "wrap:parms", functionParamsList); + +    /* Check input/output arguments count */ +    int maxInputArguments = emit_num_arguments(functionParamsList); +    int minInputArguments = emit_num_required(functionParamsList); +    int minOutputArguments = 0; +    int maxOutputArguments = 1; + +    if (!emit_isvarargs(functionParamsList)) { +      Printf(wrapper->code, "SWIG_CheckInputArgument(pvApiCtx, $mininputarguments, $maxinputarguments);\n"); +    } +    else { +      Printf(wrapper->code, "SWIG_CheckInputArgumentAtLeast(pvApiCtx, $mininputarguments-1);\n"); +    } +    Printf(wrapper->code, "SWIG_CheckOutputArgument(pvApiCtx, $minoutputarguments, $maxoutputarguments);\n"); + +    /* Set context */ +    Printf(wrapper->code, "SWIG_Scilab_SetFuncName(fname);\n"); +    Printf(wrapper->code, "SWIG_Scilab_SetApiContext(pvApiCtx);\n"); + +    /* Write typemaps(in) */ + +    for (paramIndex = 0, param = functionParamsList; paramIndex < maxInputArguments; ++paramIndex) { +      // Ignore parameter if the typemap specifies numinputs=0 +      while (checkAttribute(param, "tmap:in:numinputs", "0")) { +	param = Getattr(param, "tmap:in:next"); +      } + +      SwigType *paramType = Getattr(param, "type"); +      String *paramTypemap = Getattr(param, "tmap:in"); + +      if (paramTypemap) { +	// Replace $input by the position on Scilab stack +	String *source = NewString(""); +	Printf(source, "%d", paramIndex + 1); +	Setattr(param, "emit:input", source); +	Replaceall(paramTypemap, "$input", Getattr(param, "emit:input")); + +	if (Getattr(param, "wrap:disown") || (Getattr(param, "tmap:in:disown"))) { +	  Replaceall(paramTypemap, "$disown", "SWIG_POINTER_DISOWN"); +	} else { +	  Replaceall(paramTypemap, "$disown", "0"); +	} + +	if (paramIndex >= minInputArguments) {	/* Optional input argument management */ +	  Printf(wrapper->code, "if (SWIG_NbInputArgument(pvApiCtx) > %d) {\n%s\n}\n", paramIndex, paramTypemap); +	} else { +	  Printf(wrapper->code, "%s\n", paramTypemap); +	} +	param = Getattr(param, "tmap:in:next"); +      } else { +	Swig_warning(WARN_TYPEMAP_IN_UNDEF, input_file, line_number, "Unable to use type %s as a function argument.\n", SwigType_str(paramType, 0)); +	break; +      } +    } + +    /* TODO write constraints */ + +    Setattr(node, "wrap:name", overloadedName); + +    /* Emit the function call */ +    Swig_director_emit_dynamic_cast(node, wrapper); +    String *functionActionCode = emit_action(node); + +    /* Insert the return variable */ +    emit_return_variable(node, functionReturnType, wrapper); + +    /* Return the function value if necessary */ +    String *functionReturnTypemap = Swig_typemap_lookup_out("out", node, Swig_cresult_name(), wrapper, functionActionCode); +    if (functionReturnTypemap) { +      // Result is actually the position of output value on stack +      if (Len(functionReturnTypemap) > 0) { +	Printf(wrapper->code, "SWIG_Scilab_SetOutputPosition(%d);\n", 1); +      } +      Replaceall(functionReturnTypemap, "$result", "1"); + +      if (GetFlag(node, "feature:new")) { +	Replaceall(functionReturnTypemap, "$owner", "1"); +      } else { +	Replaceall(functionReturnTypemap, "$owner", "0"); +      } + +      Printf(wrapper->code, "%s\n", functionReturnTypemap); + +      /* If the typemap is not empty, the function return one more argument than the typemaps gives */ +      if (Len(functionReturnTypemap) > 0) { +	minOutputArguments++; +	maxOutputArguments++; +      } +      Delete(functionReturnTypemap); + +    } else { +      Swig_warning(WARN_TYPEMAP_OUT_UNDEF, input_file, line_number, "Unable to use return type %s in function %s.\n", SwigType_str(functionReturnType, 0), +		   functionName); +    } + +    /* Write typemaps(out) */ +    for (param = functionParamsList; param;) { +      String *paramTypemap = Getattr(param, "tmap:argout"); +      if (paramTypemap) { +	minOutputArguments++; +	maxOutputArguments++; +	Printf(wrapper->code, "SWIG_Scilab_SetOutputPosition(%d);\n", minOutputArguments); +	String *result = NewString(""); +	Printf(result, "%d", minOutputArguments); +	Replaceall(paramTypemap, "$result", result); +	Printf(wrapper->code, "%s\n", paramTypemap); +	Delete(paramTypemap); +	param = Getattr(param, "tmap:argout:next"); +      } else { +	param = nextSibling(param); +      } +    } +    /* Add cleanup code */ +    for (param = functionParamsList; param;) { +      String *tm; +      if ((tm = Getattr(param, "tmap:freearg"))) { +	if (tm && (Len(tm) != 0)) { +	  Printf(wrapper->code, "%s\n", tm); +	} +	param = Getattr(param, "tmap:freearg:next"); +      } else { +	param = nextSibling(param); +      } +    } + +    /* See if there is any return cleanup code */ +    String *tm; +    if ((tm = Swig_typemap_lookup("ret", node, Swig_cresult_name(), 0))) { +      Printf(wrapper->code, "%s\n", tm); +      Delete(tm); +    } + +    /* Close the function(ok) */ +    Printv(wrapper->code, "return SWIG_OK;\n", NIL); +    Printv(wrapper->code, "}\n", NIL); + +    /* Add the failure cleanup code */ +    /* TODO */ + +    /* Final substitutions if applicable */ +    Replaceall(wrapper->code, "$symname", functionName); + +    /* Set CheckInputArgument and CheckOutputArgument input arguments */ +    if (maxOutputArguments < 1) { +      maxOutputArguments = 1; +    } +    if (minOutputArguments == 1) { +      minOutputArguments = 0; +    } +    String *argnumber = NewString(""); +    Printf(argnumber, "%d", minInputArguments); +    Replaceall(wrapper->code, "$mininputarguments", argnumber); + +    argnumber = NewString(""); +    Printf(argnumber, "%d", maxInputArguments); +    Replaceall(wrapper->code, "$maxinputarguments", argnumber); + +    argnumber = NewString(""); +    Printf(argnumber, "%d", minOutputArguments); +    Replaceall(wrapper->code, "$minoutputarguments", argnumber); + +    argnumber = NewString(""); +    Printf(argnumber, "%d", maxOutputArguments); +    Replaceall(wrapper->code, "$maxoutputarguments", argnumber); + +    /* Dump the function out */ +    Wrapper_print(wrapper, wrappersSection); + +    /* Update builder.sce contents */ +    if (isLastOverloaded) { +      addFunctionToScilab(functionName, smallFunctionName, wrapperName); +      dispatchFunction(node); +    } + +    if (!isOverloaded) { +      addFunctionToScilab(functionName, smallFunctionName, wrapperName); +    } + +    /* tidy up */ +    Delete(overloadedName); +    Delete(wrapperName); +    DelWrapper(wrapper); + +    return SWIG_OK; +  } + +  /* ----------------------------------------------------------------------- +   * dispatchFunction() +   * ----------------------------------------------------------------------- */ + +  void dispatchFunction(Node *node) { +    Wrapper *wrapper = NewWrapper(); + +    String *functionName = Getattr(node, "sym:name"); +    String *wrapperName = Swig_name_wrapper(functionName); +    int maxargs = 0; + +    /* Generate the dispatch function */ +    String *dispatch = Swig_overload_dispatch(node, "return %s(SWIG_GatewayArguments);", &maxargs); +    String *tmp = NewString(""); + +    Printv(wrapper->def, "SWIGEXPORT int ", wrapperName, "(SWIG_GatewayParameters) {\n", NIL); + +    /* Get the number of the parameters */ +    Wrapper_add_local(wrapper, "argc", "int argc = SWIG_NbInputArgument(pvApiCtx)"); +    Printf(tmp, "int argv[%d] = {", maxargs); +    for (int j = 0; j < maxargs; ++j) { +      Printf(tmp, "%s%d", j ? "," : " ", j + 1); +    } +    Printf(tmp, "}"); +    Wrapper_add_local(wrapper, "argv", tmp); + +    Printf(wrapper->code, "SWIG_Scilab_SetApiContext(pvApiCtx);\n"); + +    /* Dump the dispatch function */ +    Printv(wrapper->code, dispatch, "\n", NIL); +    Printf(wrapper->code, "Scierror(999, _(\"No matching function for overload\"));\n"); +    Printf(wrapper->code, "return SWIG_ERROR;\n"); +    Printv(wrapper->code, "}\n", NIL); +    Wrapper_print(wrapper, wrappersSection); + +    Delete(tmp); +    DelWrapper(wrapper); +    Delete(dispatch); +    Delete(wrapperName); +  } + +  /* ----------------------------------------------------------------------- +   * variableWrapper() +   * ----------------------------------------------------------------------- */ + +  virtual int variableWrapper(Node *node) { + +    /* Get information about variable */ +    String *origVariableName = Getattr(node, "name");	// Ex: Shape::nshapes +    String *variableName = Getattr(node, "sym:name");	// Ex; Shape_nshapes (can be used for function names, ...) +    String *smallVariableName = createSmallIdentifierName(variableName, SCILAB_IDENTIFIER_NAME_CHAR_MAX - 4); + +    /* Manage GET function */ +    Wrapper *getFunctionWrapper = NewWrapper(); +    String *getFunctionName = Swig_name_get(NSPACE_TODO, variableName); +    String *scilabGetFunctionName = Swig_name_get(NSPACE_TODO, variableName); +    String *scilabGetSmallFunctionName = Swig_name_get(NSPACE_TODO, smallVariableName); + +    Setattr(node, "wrap:name", getFunctionName); +    Printv(getFunctionWrapper->def, "SWIGEXPORT int ", getFunctionName, "(SWIG_GatewayParameters) {\n", NIL); + +    /* Check the number of input and output */ +    Printf(getFunctionWrapper->def, "SWIG_CheckInputArgument(pvApiCtx, 0, 0);\n"); +    Printf(getFunctionWrapper->def, "SWIG_CheckOutputArgument(pvApiCtx, 0, 1);\n"); +    Printf(getFunctionWrapper->def, "SWIG_Scilab_SetApiContext(pvApiCtx);\n"); + +    String *varoutTypemap = Swig_typemap_lookup("varout", node, origVariableName, 0); +    if (varoutTypemap != NULL) { +      Printf(getFunctionWrapper->code, "SWIG_Scilab_SetOutputPosition(%d);\n", 1); +      Replaceall(varoutTypemap, "$value", origVariableName); +      Replaceall(varoutTypemap, "$result", "1"); +      emit_action_code(node, getFunctionWrapper->code, varoutTypemap); +      Delete(varoutTypemap); +    } +    Append(getFunctionWrapper->code, "return SWIG_OK;\n"); +    Append(getFunctionWrapper->code, "}\n"); +    Wrapper_print(getFunctionWrapper, wrappersSection); + +    /* Add function to builder table */ +    addFunctionToScilab(scilabGetFunctionName, scilabGetSmallFunctionName, getFunctionName); + +    /* Manage SET function */ +    if (is_assignable(node)) { +      Wrapper *setFunctionWrapper = NewWrapper(); +      String *setFunctionName = Swig_name_set(NSPACE_TODO, variableName); +      String *scilabSetFunctionName = Swig_name_set(NSPACE_TODO, variableName); +      String *scilabSetSmallFunctionName = Swig_name_set(NSPACE_TODO, smallVariableName); + +      Setattr(node, "wrap:name", setFunctionName); +      Printv(setFunctionWrapper->def, "SWIGEXPORT int ", setFunctionName, "(SWIG_GatewayParameters) {\n", NIL); + +      /* Check the number of input and output */ +      Printf(setFunctionWrapper->def, "SWIG_CheckInputArgument(pvApiCtx, 1, 1);\n"); +      Printf(setFunctionWrapper->def, "SWIG_CheckOutputArgument(pvApiCtx, 0, 1);\n"); +      Printf(setFunctionWrapper->def, "SWIG_Scilab_SetApiContext(pvApiCtx);\n"); + +      String *varinTypemap = Swig_typemap_lookup("varin", node, origVariableName, 0); +      if (varinTypemap != NULL) { +	Replaceall(varinTypemap, "$input", "1"); +	emit_action_code(node, setFunctionWrapper->code, varinTypemap); +	Delete(varinTypemap); +      } +      Append(setFunctionWrapper->code, "return SWIG_OK;\n"); +      Append(setFunctionWrapper->code, "}\n"); +      Wrapper_print(setFunctionWrapper, wrappersSection); + +      /* Add function to builder table */ +      addFunctionToScilab(scilabSetFunctionName, scilabSetSmallFunctionName, setFunctionName); + +      DelWrapper(setFunctionWrapper); +    } +    DelWrapper(getFunctionWrapper); + +    return SWIG_OK; +  } + +  /* ----------------------------------------------------------------------- +   * constantWrapper() +   * ----------------------------------------------------------------------- */ + +  virtual int constantWrapper(Node *node) { + +    /* Get the useful information from the node */ +    String *nodeName = Getattr(node, "name"); +    SwigType *type = Getattr(node, "type"); +    String *constantName = Getattr(node, "sym:name"); +    String *rawValue = Getattr(node, "rawval"); +    String *constantValue = rawValue ? rawValue : Getattr(node, "value"); +    String *constantTypemap = NULL; + +    // If feature scilab:const enabled, constants & enums are wrapped to Scilab variables +    if (GetFlag(node, "feature:scilab:const")) { +      bool isConstant = ((SwigType_issimple(type)) || (SwigType_type(type) == T_STRING)); +      bool isEnum = (Cmp(nodeType(node), "enumitem") == 0); + +      if (isConstant || isEnum) { +	if (isEnum) { +	  Setattr(node, "type", "double"); +	  constantValue = Getattr(node, "value"); +	} + +	constantTypemap = Swig_typemap_lookup("scilabconstcode", node, nodeName, 0); +	if (constantTypemap != NULL) { + +	  Setattr(node, "wrap:name", constantName); +	  Replaceall(constantTypemap, "$result", constantName); +	  Replaceall(constantTypemap, "$value", constantValue); + +	  emit_action_code(node, variablesCode, constantTypemap); +	  Delete(constantTypemap); +	  return SWIG_OK; +	} +      } +    } + +    /* Create variables for member pointer constants, not supported by typemaps (like Python wrapper does) */ +    if (SwigType_type(type) == T_MPOINTER) { +      String *wname = Swig_name_wrapper(constantName); +      String *str = SwigType_str(type, wname); +      Printf(headerSection, "static %s = %s;\n", str, constantValue); +      Delete(str); +      constantValue = wname; +    } + +    // Constant names can have SCILAB_VARIABLE_NAME_CHAR_MAX because of suffixes "_get" added to function +    String *smallConstantName = createSmallIdentifierName(constantName, SCILAB_IDENTIFIER_NAME_CHAR_MAX - 4); + +    /* Create GET function to get the constant value */ +    Wrapper *getFunctionWrapper = NewWrapper(); +    String *getFunctionName = Swig_name_get(NSPACE_TODO, constantName); +    String *scilabGetSmallFunctionName = Swig_name_get(NSPACE_TODO, smallConstantName); +    Setattr(node, "wrap:name", getFunctionName); +    Setattr(node, "wrap:name", getFunctionName); +    Printv(getFunctionWrapper->def, "SWIGEXPORT int ", getFunctionName, "(SWIG_GatewayParameters) {\n", NIL); + +    /* Check the number of input and output */ +    Printf(getFunctionWrapper->def, "SWIG_CheckInputArgument(pvApiCtx, 0, 0);\n"); +    Printf(getFunctionWrapper->def, "SWIG_CheckOutputArgument(pvApiCtx, 0, 1);\n"); +    Printf(getFunctionWrapper->def, "SWIG_Scilab_SetApiContext(pvApiCtx);\n"); + +    constantTypemap = Swig_typemap_lookup("constcode", node, nodeName, 0); +    if (constantTypemap != NULL) { +      Printf(getFunctionWrapper->code, "SWIG_Scilab_SetOutputPosition(%d);\n", 1); +      Replaceall(constantTypemap, "$value", constantValue); +      Replaceall(constantTypemap, "$result", "1"); +      emit_action_code(node, getFunctionWrapper->code, constantTypemap); +      Delete(constantTypemap); +    } + +    /* Dump the wrapper function */ +    Append(getFunctionWrapper->code, "return SWIG_OK;\n"); +    Append(getFunctionWrapper->code, "}\n"); +    Wrapper_print(getFunctionWrapper, wrappersSection); + +    /* Add the function to Scilab  */ +    addFunctionToScilab(getFunctionName, scilabGetSmallFunctionName, getFunctionName); + +    DelWrapper(getFunctionWrapper); + +    return SWIG_OK; +  } + +  /* --------------------------------------------------------------------- +   * enumvalueDeclaration() +   * --------------------------------------------------------------------- */ + +  virtual int enumvalueDeclaration(Node *node) { +    static int iPreviousEnumValue = 0; + +    if (GetFlag(node, "feature:scilab:const")) { +      // Compute the "absolute" value of enum if needed +      // (most of time enum values are a linked list of relative values) +      String *enumValue = Getattr(node, "enumvalue"); +      String *enumValueEx = Getattr(node, "enumvalueex"); + +      // First enum value ? +      String *firstenumitem = Getattr(node, "firstenumitem"); +      if (firstenumitem) { +	if (enumValue) { +	  // Value is in 'enumvalue' +	  iPreviousEnumValue = atoi(Char(enumValue)); +	} else if (enumValueEx) { +	  // Or value is in 'enumValueEx' +	  iPreviousEnumValue = atoi(Char(enumValueEx)); + +	  enumValue = NewString(""); +	  Printf(enumValue, "%d", iPreviousEnumValue); +	  Setattr(node, "enumvalue", enumValue); +	} +      } else if (!enumValue && enumValueEx) { +	// Value is not specified, set it by incrementing last value +	enumValue = NewString(""); +	Printf(enumValue, "%d", ++iPreviousEnumValue); +	Setattr(node, "enumvalue", enumValue); +      } +      // Enums in Scilab are mapped to double +      Setattr(node, "type", "double"); +    } + +    return Language::enumvalueDeclaration(node); +  } + +  /* ----------------------------------------------------------------------- +   * addHelperFunctions() +   * ----------------------------------------------------------------------- */ + +  void addHelperFunctions() { +    addFunctionToScilab("SWIG_this", "SWIG_this", "SWIG_this"); +    addFunctionToScilab("SWIG_ptr", "SWIG_ptr", "SWIG_ptr"); +  } + +  /* ----------------------------------------------------------------------- +   * addFunctionToScilab() +   * Declare a wrapped function in Scilab (builder, gateway, XML, ...) +   * ----------------------------------------------------------------------- */ + +  void addFunctionToScilab(const_String_or_char_ptr scilabFunctionName, const_String_or_char_ptr scilabSmallFunctionName, const_String_or_char_ptr wrapperFunctionName) { +    if (!generateBuilder) +      addFunctionInGatewayHeader(scilabFunctionName, scilabSmallFunctionName, wrapperFunctionName); + +    if (generateBuilder) { +      addFunctionInScriptTable(scilabFunctionName, scilabSmallFunctionName, wrapperFunctionName, builderCode5, builderCode6); +    } + +    if (createLoader) { +      addFunctionInLoader(scilabFunctionName, scilabSmallFunctionName); +    } + +    if (gatewayXMLFile) { +      Printf(gatewayXML, "<PRIMITIVE gatewayId=\"%s\" primitiveId=\"%d\" primitiveName=\"%s\"/>\n", gatewayID, primitiveID++, scilabSmallFunctionName); +    } +  } + + +  /* ----------------------------------------------------------------------- +   * createBuilderCode() +   * ----------------------------------------------------------------------- */ + +  void createBuilderFile(String *outputFilename) { +    String *builderFilename = NewStringf("builder.sce"); +    builderFile = NewFile(builderFilename, "w", SWIG_output_files()); +    if (!builderFile) { +      FileErrorDisplay(builderFilename); +      Exit(EXIT_FAILURE); +    } +    emitBanner(builderFile); + +    builderFunctionCount = 0; +    builderCode = NewString(""); +    builderCode5 = NewString(""); +    builderCode6 = NewString(""); +    Printf(builderCode, "mode(-1);\n"); +    Printf(builderCode, "lines(0);\n");	/* Useful for automatic tests */ + +    // Scilab needs to be in the build directory +    Printf(builderCode, "originaldir = pwd();\n"); +    Printf(builderCode, "builddir = get_absolute_file_path('builder.sce');\n"); +    Printf(builderCode, "cd(builddir);\n"); + +    Printf(builderCode, "ilib_verbose(%s);\n", verboseBuildLevel); + +    Printf(builderCode, "libs = [];\n"); + +    // Flags from command line arguments +    Printf(builderCode, "cflags = \"\";\n"); +    for (int i = 0; i < Len(cflags); i++) { +      String *cflag = Getitem(cflags, i); +      Printf(builderCode, "cflags = cflags + \" %s\";\n", cflag); +    } + +    if (Len(ldflags) > 0) { +      for (int i = 0; i < Len(ldflags); i++) { +	String *ldflag = Getitem(ldflags, i); +	if (i == 0) { +	  Printf(builderCode, "ldflags = \"%s\";\n", ldflag); +	} else { +	  Printf(builderCode, "ldflags = ldflags + \" %s\";\n", ldflag); +	} +      } +    } else { +      Printf(builderCode, "ldflags = \"\";\n"); +    } + +    // External script to set flags +    if (buildFlagsScript) { +      Printf(builderCode, "exec(\"%s\");\n", buildFlagsScript); +      Printf(builderCode, "cflags = cflags + getCompilationFlags();\n"); +      Printf(builderCode, "ldflags = ldflags + getLinkFlags();\n"); +    } +    // Additional sources +    Insert(sourceFileList, 0, outputFilename); +    for (int i = 0; i < Len(sourceFileList); i++) { +      String *sourceFile = Getitem(sourceFileList, i); +      if (i == 0) { +	Printf(builderCode, "files = \"%s\";\n", sourceFile); +      } else { +	Printf(builderCode, "files($ + 1) = \"%s\";\n", sourceFile); +      } +    } + +    Printf(builderCode5, "table = [ ..\n"); +    Printf(builderCode6, "table = [ ..\n"); +  } + +  /* ----------------------------------------------------------------------- +   * addFunctionInBuilderCode() +   * Add a function wrapper in the function table of generated builder script +   * ----------------------------------------------------------------------- */ + +  void addFunctionInScriptTable(const_String_or_char_ptr scilabFunctionName, const_String_or_char_ptr scilabSmallFunctionName, const_String_or_char_ptr wrapperFunctionName, String *scriptCode5, String *scriptCode6) { +    if (++builderFunctionCount % 10 == 0) { +      Printf(scriptCode5, "];\ntable = [table; ..\n"); +      Printf(scriptCode6, "];\ntable = [table; ..\n"); +    } +    Printf(scriptCode5, "\"%s\",\"%s\"; ..\n", scilabSmallFunctionName, wrapperFunctionName); +    Printf(scriptCode6, "\"%s\",\"%s\"; ..\n", scilabFunctionName, wrapperFunctionName); +  } + +  /* ----------------------------------------------------------------------- +   * saveBuilderFile() +   * ----------------------------------------------------------------------- */ + +  void saveBuilderFile(String *gatewayName) { +    Printf(builderCode5, "];\n"); +    Printf(builderCode6, "];\n"); + +    if (Equal(builderCode5, builderCode6)) { +      Append(builderCode, builderCode6); +    } else { +      Printf(builderCode, "ver = getversion('scilab');\n"); +      Printf(builderCode, "if ver(1) < 6 then\n"); +      Printf(builderCode, "  // version is less or equal to 5.5.2\n"); +      Printf(builderCode, "  \n"); +      Append(builderCode, builderCode5); +      Printf(builderCode, "  \n"); +      Printf(builderCode, "else\n"); +      Printf(builderCode, "  // version is 6.0.0 or more\n"); +      Printf(builderCode, "  \n"); +      Append(builderCode, builderCode6); +      Printf(builderCode, "  \n"); +      Printf(builderCode, "end\n"); +    } + +    Printf(builderCode, "ierr = 0;\n"); +    Printf(builderCode, "if ~isempty(table) then\n"); +    Printf(builderCode, "  ierr = execstr(\"ilib_build(''%s'', table, files, libs, [], ldflags, cflags);\", 'errcatch');\n", gatewayName); +    Printf(builderCode, "  if ierr <> 0 then\n"); +    Printf(builderCode, "    err_msg = lasterror();\n"); +    Printf(builderCode, "  end\n"); +    Printf(builderCode, "end\n"); +    Printf(builderCode, "cd(originaldir);\n"); +    Printf(builderCode, "if ierr <> 0 then\n"); +    Printf(builderCode, "  error(ierr, err_msg);\n"); +    Printf(builderCode, "end\n"); +    Printv(builderFile, builderCode, NIL); + +    Delete(builderCode); +    Delete(builderFile); +  } + +  /* ----------------------------------------------------------------------- +   * createGatewayXMLFile() +   * This XML file is used by Scilab in the context of internal modules +   * ----------------------------------------------------------------------- */ + +  void createGatewayXMLFile(String *gatewayName) { +    String *gatewayXMLFilename = NewStringf("%s_gateway.xml", gatewayName); +    gatewayXMLFile = NewFile(gatewayXMLFilename, "w", SWIG_output_files()); +    if (!gatewayXMLFile) { +      FileErrorDisplay(gatewayXMLFilename); +      Exit(EXIT_FAILURE); +    } +    // Add a slightly modified SWIG banner to the gateway XML ("--modify" is illegal in XML) +    gatewayXML = NewString(""); +    Printf(gatewayXML, "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n"); +    Printf(gatewayXML, "<!--\n"); +    Swig_banner_target_lang(gatewayXML, ""); +    Printf(gatewayXML, "-->\n"); +    Printf(gatewayXML, "<GATEWAY name=\"%s\">\n", gatewayName); + +    primitiveID = 1; +  } + +  /* ----------------------------------------------------------------------- +   * saveGatewayXMLFile() +   * ----------------------------------------------------------------------- */ + +  void saveGatewayXMLFile() { +    Printf(gatewayXML, "</GATEWAY>\n"); +    Printv(gatewayXMLFile, gatewayXML, NIL); +    Delete(gatewayXMLFile); +  } + +  /* ----------------------------------------------------------------------- +   * startGatewayHeader() +   * Start the gateway header +   * ----------------------------------------------------------------------- */ +  void startGatewayHeader(String *gatewayLibraryName) { +    gatewayHeader = NewString(""); +    Printf(gatewayHeader, "\n"); + +    gatewayHeaderV6 = NewString(""); +    Printf(gatewayHeaderV6, "#ifdef __cplusplus\n"); +    Printf(gatewayHeaderV6, "extern \"C\" {\n"); +    Printf(gatewayHeaderV6, "#endif\n"); +    Printf(gatewayHeaderV6, "#include \"c_gateway_prototype.h\"\n"); +    Printf(gatewayHeaderV6, "#include \"addfunction.h\"\n"); +    Printf(gatewayHeaderV6, "#ifdef __cplusplus\n"); +    Printf(gatewayHeaderV6, "}\n"); +    Printf(gatewayHeaderV6, "#endif\n"); +    Printf(gatewayHeaderV6, "\n"); +    Printf(gatewayHeaderV6, "#define MODULE_NAME L\"%s\"\n", gatewayLibraryName); +    Printf(gatewayHeaderV6, "#ifdef __cplusplus\n"); +    Printf(gatewayHeaderV6, "extern \"C\"\n"); +    Printf(gatewayHeaderV6, "#endif\n"); +    Printf(gatewayHeaderV6, "SWIGEXPORT int %s(wchar_t *pwstFuncName) {\n", gatewayLibraryName); +    Printf(gatewayHeaderV6, "\n"); +  } + +  /* ----------------------------------------------------------------------- +   * addFunctionInGatewayHeader() +   * Add a function in the gateway header +   * ----------------------------------------------------------------------- */ + +  void addFunctionInGatewayHeader(const_String_or_char_ptr scilabFunctionName, const_String_or_char_ptr scilabSmallFunctionName, const_String_or_char_ptr wrapperFunctionName) { +    if (gatewayHeaderV5 == NULL) { +      gatewayHeaderV5 = NewString(""); +      Printf(gatewayHeaderV5, "static GenericTable Tab[] = {\n"); +    } else +      Printf(gatewayHeaderV5, ",\n"); +    Printf(gatewayHeaderV5, " {(Myinterfun)sci_gateway, (GT)%s, (char *)\"%s\"}", wrapperFunctionName, scilabSmallFunctionName); + +    Printf(gatewayHeaderV6, "if (wcscmp(pwstFuncName, L\"%s\") == 0) { addCStackFunction((wchar_t *)L\"%s\", &%s, (wchar_t *)MODULE_NAME); }\n", scilabFunctionName, scilabFunctionName, wrapperFunctionName); +  } + +  /* ----------------------------------------------------------------------- +   * terminateGatewayHeader() +   * Terminates the gateway header +   * ----------------------------------------------------------------------- */ + +  void terminateGatewayHeader(String *gatewayLibraryName) { +    Printf(gatewayHeaderV5, "};\n"); +    Printf(gatewayHeaderV5, "\n"); +    Printf(gatewayHeaderV5, "#ifdef __cplusplus\n"); +    Printf(gatewayHeaderV5, "extern \"C\" {\n"); +    Printf(gatewayHeaderV5, "#endif\n"); +    Printf(gatewayHeaderV5, "SWIGEXPORT int C2F(%s)() {\n", gatewayLibraryName); +    Printf(gatewayHeaderV5, "  Rhs = Max(0, Rhs);\n"); +    Printf(gatewayHeaderV5, "  if (*(Tab[Fin-1].f) != NULL) {\n"); +    Printf(gatewayHeaderV5, "    if(pvApiCtx == NULL) {\n"); +    Printf(gatewayHeaderV5, "      pvApiCtx = (StrCtx *)MALLOC(sizeof(StrCtx));\n"); +    Printf(gatewayHeaderV5, "    }\n"); +    Printf(gatewayHeaderV5, "    pvApiCtx->pstName = (char *)Tab[Fin-1].name;\n"); +    Printf(gatewayHeaderV5, "    (*(Tab[Fin-1].f))(Tab[Fin-1].name,(GatefuncH)Tab[Fin-1].F);\n"); +    Printf(gatewayHeaderV5, "  }\n"); +    Printf(gatewayHeaderV5, "  return 0;\n"); +    Printf(gatewayHeaderV5, "}\n"); +    Printf(gatewayHeaderV5, "\n"); +    Printf(gatewayHeaderV5, "#ifdef __cplusplus\n"); +    Printf(gatewayHeaderV5, "}\n"); +    Printf(gatewayHeaderV5, "#endif\n"); + +    Printf(gatewayHeaderV6, "return 1;\n"); +    Printf(gatewayHeaderV6, "};\n"); + +    Printf(gatewayHeader, "#if SWIG_SCILAB_VERSION >= 600\n"); +    Printv(gatewayHeader, gatewayHeaderV6, NIL); +    Printf(gatewayHeader, "#else\n"); +    Printv(gatewayHeader, gatewayHeaderV5, NIL); +    Printf(gatewayHeader, "#endif\n"); +  } + + +  /* ----------------------------------------------------------------------- +   * createLoaderScriptFile() +   * Creates the loader script file (loader.sce) +   * ----------------------------------------------------------------------- */ + +  void createLoaderFile(String *gatewayLibraryName) { +    String *loaderFilename = NewString("loader.sce"); +    loaderFile = NewFile(loaderFilename, "w", SWIG_output_files()); +    if (!loaderFile) { +      FileErrorDisplay(loaderFilename); +      Exit(EXIT_FAILURE); +    } + +    emitBanner(loaderFile); + +    loaderFunctionCount = 0; +    loaderScript = NewString("function loader_function()\n"); +    Printf(loaderScript, "  p = get_absolute_file_path('loader.sce');\n", gatewayLibraryName); +    Printf(loaderScript, "  [bOK, ilib] = c_link('%s');\n", gatewayLibraryName); +    Printf(loaderScript, "  if bOK then\n"); +    Printf(loaderScript, "    ulink(ilib);\n"); +    Printf(loaderScript, "  end\n"); +    loaderScript5 = NewString("    list_functions = [ ..\n"); +    loaderScript6 = NewString("    list_functions = [ ..\n"); +  } + +  /* ----------------------------------------------------------------------- +   * addFunctionInLoaderScript() +   * Add a function in the loader script table +   * ----------------------------------------------------------------------- */ + +  void addFunctionInLoader(const_String_or_char_ptr scilabFunctionName, const_String_or_char_ptr scilabSmallFunctionName) { +    if (++loaderFunctionCount % 10 == 0) { +      Printf(loaderScript5, "    ];\n    list_functions = [list_functions; ..\n"); +      Printf(loaderScript6, "    ];\n    list_functions = [list_functions; ..\n"); +    } +    Printf(loaderScript5, "      '%s'; ..\n", scilabSmallFunctionName); +    Printf(loaderScript6, "      '%s'; ..\n", scilabFunctionName); +  } + +  /* ----------------------------------------------------------------------- +   * saveLoaderScriptFile() +   * Terminates and saves the loader script +   * ----------------------------------------------------------------------- */ + +  void saveLoaderFile(String *gatewayLibraryName) { +    Printf(loaderScript5, "    ];\n"); +    Printf(loaderScript6, "    ];\n"); + +    if (Equal(loaderScript5, loaderScript6)) { +      Append(loaderScript, loaderScript6); +    } else { +      Printf(loaderScript, "  ver = getversion('scilab');\n"); +      Printf(loaderScript, "  if ver(1) < 6 then\n"); +      Printf(loaderScript, "    // version is less or equal to 5.5.2\n"); +      Printf(loaderScript, "    \n"); +      Append(loaderScript, loaderScript5); +      Delete(loaderScript5); +      Printf(loaderScript, "    \n"); +      Printf(loaderScript, "  else\n"); +      Printf(loaderScript, "    // version is 6.0.0 or more\n"); +      Printf(loaderScript, "    \n"); +      Append(loaderScript, loaderScript6); +      Delete(loaderScript6); +      Printf(loaderScript, "    \n"); +      Printf(loaderScript, "  end\n"); +    } + +    Printf(loaderScript, "  addinter(p + '%s' + getdynlibext(), '%s', list_functions);\n", gatewayLibraryName, gatewayLibraryName); +    Printf(loaderScript, "endfunction\n"); +    Printf(loaderScript, "loader_function();\n"); +    Printf(loaderScript, "clear loader_function;\n"); +    Printv(loaderFile, loaderScript, NIL); + +    Delete(loaderScript); +    Delete(loaderFile); +  } + +  /* ----------------------------------------------------------------------- +   * createSmallIdentifierName() +   * Create a Scilab small identifier to be used by Scilab 5 +   * ----------------------------------------------------------------------- */ + +  String* createSmallIdentifierName(String* name, int outputLen = SCILAB_IDENTIFIER_NAME_CHAR_MAX) { +    char* s = Char(name); +    int nameLen = Len(s); + +    // truncate and preserve common suffix +    if (outputLen > 4 && nameLen > outputLen) { +      String* smallName = NewStringWithSize(name, outputLen); +      char* smallNameStr = (char*) Data(smallName); + +      if (s[nameLen-4] == '_' && s[nameLen - 3] == 'g' && s[nameLen - 2] == 'e' && s[nameLen - 1] == 't') { +        // get +        memcpy(&smallNameStr[outputLen - 4], &s[nameLen - 4], 4); +      } else if (s[nameLen-4] == '_' && s[nameLen - 3] == 's' && s[nameLen - 2] == 'e' && s[nameLen - 1] == 't') { +        // set +        memcpy(&smallNameStr[outputLen - 4], &s[nameLen - 4], 4); +      } + +      return smallName; +    } +     +    return name; +  } + +}; + +extern "C" Language *swig_scilab(void) { +  return new SCILAB(); +} diff --git a/contrib/tools/swig/Source/Modules/swigmain.cxx b/contrib/tools/swig/Source/Modules/swigmain.cxx new file mode 100644 index 00000000000..d553fe8930c --- /dev/null +++ b/contrib/tools/swig/Source/Modules/swigmain.cxx @@ -0,0 +1,265 @@ +/* -----------------------------------------------------------------------------  + * This file is part of SWIG, which is licensed as a whole under version 3  + * (or any later version) of the GNU General Public License. Some additional + * terms also apply to certain portions of SWIG. The full details of the SWIG + * license and copyrights can be found in the LICENSE and COPYRIGHT files + * included with the SWIG source code as distributed by the SWIG developers + * and at https://www.swig.org/legal.html. + * + * swigmain.cxx + * + * Simplified Wrapper and Interface Generator  (SWIG) + * + * This file is the main entry point to SWIG.  It collects the command + * line options, registers built-in language modules, and instantiates + * a module for code generation.   If adding new language modules + * to SWIG, you would modify this file. + * ----------------------------------------------------------------------------- */ + +#include "swigmod.h" +#include <ctype.h> + +/* Module factories.  These functions are used to instantiate +   the built-in language modules.    If adding a new language +   module to SWIG, place a similar function here. Make sure +   the function has "C" linkage.  This is required so that modules +   can be dynamically loaded in future versions. */ + +extern "C" { +  Language *swig_csharp(void); +  Language *swig_d(void); +  Language *swig_go(void); +  Language *swig_guile(void); +  Language *swig_java(void); +  Language *swig_javascript(void); +  Language *swig_lua(void); +  Language *swig_mzscheme(void); +  Language *swig_ocaml(void); +  Language *swig_octave(void); +  Language *swig_perl5(void); +  Language *swig_php(void); +  Language *swig_python(void); +  Language *swig_r(void); +  Language *swig_ruby(void); +  Language *swig_scilab(void); +  Language *swig_tcl(void); +  Language *swig_xml(void); +} + +/* Association of command line options to language modules. +   Place an entry for new language modules here, keeping the +   list sorted alphabetically. */ + +static TargetLanguageModule modules[] = { +  {"-allegrocl", NULL, "ALLEGROCL", Disabled}, +  {"-chicken", NULL, "CHICKEN", Disabled}, +  {"-clisp", NULL, "CLISP", Disabled}, +  {"-cffi", NULL, "CFFI", Disabled}, +  {"-csharp", swig_csharp, "C#", Supported}, +  {"-d", swig_d, "D", Supported}, +  {"-go", swig_go, "Go", Supported}, +  {"-guile", swig_guile, "Guile", Supported}, +  {"-java", swig_java, "Java", Supported}, +  {"-javascript", swig_javascript, "Javascript", Supported}, +  {"-lua", swig_lua, "Lua", Supported}, +  {"-modula3", NULL, "Modula 3", Disabled}, +  {"-mzscheme", swig_mzscheme, "MzScheme/Racket", Experimental}, +  {"-ocaml", swig_ocaml, "OCaml", Experimental}, +  {"-octave", swig_octave, "Octave", Supported}, +  {"-perl", swig_perl5, NULL, Supported}, +  {"-perl5", swig_perl5, "Perl 5", Supported}, +  {"-php", swig_php, NULL, Supported}, +  {"-php5", NULL, "PHP 5", Disabled}, +  {"-php7", swig_php, "PHP 7 or later", Supported}, +  {"-pike", NULL, "Pike", Disabled}, +  {"-python", swig_python, "Python", Supported}, +  {"-r", swig_r, "R (aka GNU S)", Supported}, +  {"-ruby", swig_ruby, "Ruby", Supported}, +  {"-scilab", swig_scilab, "Scilab", Supported}, +  {"-sexp", NULL, "Lisp S-Expressions", Disabled}, +  {"-tcl", swig_tcl, NULL, Supported}, +  {"-tcl8", swig_tcl, "Tcl 8", Supported}, +  {"-uffi", NULL, "Common Lisp / UFFI", Disabled}, +  {"-xml", swig_xml, "XML", Supported}, +  {NULL, NULL, NULL, Disabled} +}; + +//----------------------------------------------------------------- +// main() +// +// Main program.    Initializes the files and starts the parser. +//----------------------------------------------------------------- + +void SWIG_merge_envopt(const char *env, int oargc, char *oargv[], int *nargc, char ***nargv) { +  if (!env) { +    *nargc = oargc; +    *nargv = (char **)Malloc(sizeof(char *) * (oargc + 1)); +    memcpy(*nargv, oargv, sizeof(char *) * (oargc + 1)); +    return; +  } + +  int argc = 1; +  int arge = oargc + 1024; +  char **argv = (char **) Malloc(sizeof(char *) * (arge + 1)); +  char *buffer = (char *) Malloc(2048); +  char *b = buffer; +  char *be = b + 1023; +  const char *c = env; +  while ((b != be) && *c && (argc < arge)) { +    while (isspace(*c) && *c) +      ++c; +    if (*c) { +      argv[argc] = b; +      ++argc; +    } +    while ((b != be) && *c && !isspace(*c)) { +      *(b++) = *(c++); +    } +    *b++ = 0; +  } + +  argv[0] = oargv[0]; +  for (int i = 1; (i < oargc) && (argc < arge); ++i, ++argc) { +    argv[argc] = oargv[i]; +  } +  argv[argc] = NULL; + +  *nargc = argc; +  *nargv = argv; +} + +static void insert_option(int *argc, char ***argv, int index, char const *start, char const *end) { +  int new_argc = *argc; +  char **new_argv = *argv; +  size_t option_len = end - start; + +  // Preserve the NULL pointer at argv[argc] +  new_argv = (char **)Realloc(new_argv, (new_argc + 2) * sizeof(char *)); +  memmove(&new_argv[index + 1], &new_argv[index], sizeof(char *) * (new_argc + 1 - index)); +  new_argc++; + +  new_argv[index] = (char *)Malloc(option_len + 1); +  memcpy(new_argv[index], start, option_len); +  new_argv[index][option_len] = '\0'; + +  *argc = new_argc; +  *argv = new_argv; +} + +static void merge_options_files(int *argc, char ***argv) { +  static const int BUFFER_SIZE = 4096; +  char buffer[BUFFER_SIZE]; +  int i; +  int insert; +  char **new_argv = *argv; +  int new_argc = *argc; +  FILE *f; + +  i = 1; +  while (i < new_argc) { +    if (new_argv[i] && new_argv[i][0] == '@' && (f = fopen(&new_argv[i][1], "r"))) { +      int ci; +      char *b; +      char *be = &buffer[BUFFER_SIZE]; +      int quote = 0; +      bool escape = false; + +      new_argc--; +      memmove(&new_argv[i], &new_argv[i + 1], sizeof(char *) * (new_argc - i)); +      insert = i; +      b = buffer; + +      while ((ci = fgetc(f)) != EOF) { +        const char c = static_cast<char>(ci); +        if (escape) { +          if (b != be) { +            *b = c; +            ++b; +          } +          escape = false; +        } else if (c == '\\') { +          escape = true; +        } else if (!quote && (c == '\'' || c == '"')) { +          quote = c; +        } else if (quote && c == quote) { +          quote = 0; +        } else if (isspace(c) && !quote) { +          if (b != buffer) { +            insert_option(&new_argc, &new_argv, insert, buffer, b); +            insert++; + +            b = buffer; +          } +        } else if (b != be) { +          *b = c; +          ++b; +        } +      } +      if (b != buffer) +        insert_option(&new_argc, &new_argv, insert, buffer, b); +      fclose(f); +    } else { +      ++i; +    } +  } + +  *argv = new_argv; +  *argc = new_argc; +} + +int main(int margc, char **margv) { +  int i; +  const TargetLanguageModule *language_module = 0; + +  int argc; +  char **argv; + +  SWIG_merge_envopt(getenv("SWIG_FEATURES"), margc, margv, &argc, &argv); +  merge_options_files(&argc, &argv); + +  Swig_init_args(argc, argv); + +  /* Get options */ +  for (i = 1; i < argc; i++) { +    if (argv[i]) { +      bool is_target_language_module = false; +      for (int j = 0; modules[j].name; j++) { +	if (strcmp(modules[j].name, argv[i]) == 0) { +	  language_module = &modules[j]; +	  is_target_language_module = true; +	  break; +	} +      } +      if (is_target_language_module) { +	Swig_mark_arg(i); +	if (language_module->status == Disabled) { +	  if (language_module->help) +	    Printf(stderr, "Target language option %s (%s) is no longer supported.\n", language_module->name, language_module->help); +	  else +	    Printf(stderr, "Target language option %s is no longer supported.\n", language_module->name); +	  Exit(EXIT_FAILURE); +	} +      } else if ((strcmp(argv[i], "-help") == 0) || (strcmp(argv[i], "--help") == 0)) { +	if (strcmp(argv[i], "--help") == 0) +	  strcpy(argv[i], "-help"); +	Printf(stdout, "Supported Target Language Options\n"); +	for (int j = 0; modules[j].name; j++) { +	  if (modules[j].help && modules[j].status == Supported) { +	    Printf(stdout, "     %-15s - Generate %s wrappers\n", modules[j].name, modules[j].help); +	  } +	} +	Printf(stdout, "\nExperimental Target Language Options\n"); +	for (int j = 0; modules[j].name; j++) { +	  if (modules[j].help && modules[j].status == Experimental) { +	    Printf(stdout, "     %-15s - Generate %s wrappers\n", modules[j].name, modules[j].help); +	  } +	} +	// Swig_mark_arg not called as the general -help options also need to be displayed later on +      } +    } +  } + +  int res = SWIG_main(argc, argv, language_module); + +  return res; +} diff --git a/contrib/tools/swig/Source/Modules/swigmod.h b/contrib/tools/swig/Source/Modules/swigmod.h new file mode 100644 index 00000000000..c605edf9d04 --- /dev/null +++ b/contrib/tools/swig/Source/Modules/swigmod.h @@ -0,0 +1,463 @@ +/* ----------------------------------------------------------------------------- + * This file is part of SWIG, which is licensed as a whole under version 3  + * (or any later version) of the GNU General Public License. Some additional + * terms also apply to certain portions of SWIG. The full details of the SWIG + * license and copyrights can be found in the LICENSE and COPYRIGHT files + * included with the SWIG source code as distributed by the SWIG developers + * and at https://www.swig.org/legal.html. + * + * swigmod.h + * + * Main header file for SWIG modules. + * ----------------------------------------------------------------------------- */ + +#ifndef SWIG_SWIGMOD_H +#define SWIG_SWIGMOD_H + +#include "swig.h" +#include "preprocessor.h" +#include "swigwarn.h" + +#define NOT_VIRTUAL     0 +#define PLAIN_VIRTUAL   1 +#define PURE_VIRTUAL    2 + +extern String *input_file; +extern int line_number; +extern int start_line; +extern int CPlusPlus;		// C++ mode +extern int Extend;		// Extend mode +extern int Verbose; +extern int IsVirtual; +extern int ImportMode; +extern int NoExcept;		// -no_except option +extern int Abstract;		// abstract base class +extern int SmartPointer;	// smart pointer methods being emitted +extern int SwigRuntime; + +/* Overload "argc" and "argv" */ +extern String *argv_template_string; +extern String *argc_template_string; + +/* Miscellaneous stuff */ + +#define  tab2   "  " +#define  tab4   "    " +#define  tab8   "        " + +class Dispatcher { +public: + +  Dispatcher ():cplus_mode(PUBLIC) { +  } +  virtual ~ Dispatcher () { +  } + +  virtual int emit_one(Node *n); +  virtual int emit_children(Node *n); +  virtual int defaultHandler(Node *n); + +  /* Top of the parse tree */ +  virtual int top(Node *n) = 0; + +  /* SWIG directives */ + +  virtual int applyDirective(Node *n); +  virtual int clearDirective(Node *n); +  virtual int constantDirective(Node *n); +  virtual int extendDirective(Node *n); +  virtual int fragmentDirective(Node *n); +  virtual int importDirective(Node *n); +  virtual int includeDirective(Node *n); +  virtual int insertDirective(Node *n); +  virtual int moduleDirective(Node *n); +  virtual int nativeDirective(Node *n); +  virtual int pragmaDirective(Node *n); +  virtual int typemapDirective(Node *n); +  virtual int typemapitemDirective(Node *n); +  virtual int typemapcopyDirective(Node *n); +  virtual int typesDirective(Node *n); + +  /* C/C++ parsing */ + +  virtual int cDeclaration(Node *n); +  virtual int externDeclaration(Node *n); +  virtual int enumDeclaration(Node *n); +  virtual int enumvalueDeclaration(Node *n); +  virtual int enumforwardDeclaration(Node *n); +  virtual int classDeclaration(Node *n); +  virtual int classforwardDeclaration(Node *n); +  virtual int constructorDeclaration(Node *n); +  virtual int destructorDeclaration(Node *n); +  virtual int accessDeclaration(Node *n); +  virtual int usingDeclaration(Node *n); +  virtual int namespaceDeclaration(Node *n); +  virtual int templateDeclaration(Node *n); +  virtual int lambdaDeclaration(Node *n); + +  enum AccessMode { PUBLIC, PRIVATE, PROTECTED }; + +protected: +  AccessMode cplus_mode; +}; + +/* ---------------------------------------------------------------------------- + * class language: + * + * This class defines the functions that need to be supported by the + * scripting language being used.    The translator calls these virtual + * functions to output different types of code for different languages. + * ------------------------------------------------------------------------- */ + +class Language:public Dispatcher { +public: +  Language(); +  virtual ~Language(); +  virtual int emit_one(Node *n); + +  String *directorClassName(Node *n); + +  /* Parse command line options */ + +  virtual void main(int argc, char *argv[]); + +  /* Top of the parse tree */ + +  virtual int top(Node *n); + +  /* SWIG directives */ + + +  virtual int applyDirective(Node *n); +  virtual int clearDirective(Node *n); +  virtual int constantDirective(Node *n); +  virtual int extendDirective(Node *n); +  virtual int fragmentDirective(Node *n); +  virtual int importDirective(Node *n); +  virtual int includeDirective(Node *n); +  virtual int insertDirective(Node *n); +  virtual int moduleDirective(Node *n); +  virtual int nativeDirective(Node *n); +  virtual int pragmaDirective(Node *n); +  virtual int typemapDirective(Node *n); +  virtual int typemapcopyDirective(Node *n); +  virtual int typesDirective(Node *n); + +  /* C/C++ parsing */ + +  virtual int cDeclaration(Node *n); +  virtual int externDeclaration(Node *n); +  virtual int enumDeclaration(Node *n); +  virtual int enumvalueDeclaration(Node *n); +  virtual int enumforwardDeclaration(Node *n); +  virtual int classDeclaration(Node *n); +  virtual int classforwardDeclaration(Node *n); +  virtual int constructorDeclaration(Node *n); +  virtual int destructorDeclaration(Node *n); +  virtual int accessDeclaration(Node *n); +  virtual int namespaceDeclaration(Node *n); +  virtual int usingDeclaration(Node *n); + +  /* Function handlers */ + +  virtual int functionHandler(Node *n); +  virtual int globalfunctionHandler(Node *n); +  virtual int memberfunctionHandler(Node *n); +  virtual int staticmemberfunctionHandler(Node *n); +  virtual int callbackfunctionHandler(Node *n); + +  /* Variable handlers */ + +  virtual int variableHandler(Node *n); +  virtual int globalvariableHandler(Node *n); +  virtual int membervariableHandler(Node *n); +  virtual int staticmembervariableHandler(Node *n); + +  /* C++ handlers */ + +  virtual int memberconstantHandler(Node *n); +  virtual int constructorHandler(Node *n); +  virtual int copyconstructorHandler(Node *n); +  virtual int destructorHandler(Node *n); +  virtual int classHandler(Node *n); + +  /* Miscellaneous */ + +  virtual int typedefHandler(Node *n); + +  /* Low-level code generation */ + +  virtual int constantWrapper(Node *n); +  virtual int variableWrapper(Node *n); +  virtual int functionWrapper(Node *n); +  virtual int nativeWrapper(Node *n); + +  /* C++ director class generation */ +  virtual int classDirector(Node *n); +  virtual int classDirectorInit(Node *n); +  virtual int classDirectorEnd(Node *n); +  virtual int unrollVirtualMethods(Node *n, Node *parent, List *vm, int &virtual_destructor, int protectedbase = 0); +  virtual int classDirectorConstructor(Node *n); +  virtual int classDirectorDefaultConstructor(Node *n); +  virtual int classDirectorMethod(Node *n, Node *parent, String *super); +  virtual int classDirectorConstructors(Node *n); +  virtual int classDirectorDestructor(Node *n); +  virtual int classDirectorMethods(Node *n); +  virtual int classDirectorDisown(Node *n); + +  /* Miscellaneous */ +  virtual int validIdentifier(String *s);	/* valid identifier? */ +  virtual int addSymbol(const String *s, const Node *n, const_String_or_char_ptr scope = "");	/* Add symbol        */ +  virtual int addInterfaceSymbol(const String *interface_name, Node *n, const_String_or_char_ptr scope = ""); +  virtual void dumpSymbols(); +  virtual Node *symbolLookup(const String *s, const_String_or_char_ptr scope = ""); /* Symbol lookup */ +  virtual Hash* symbolAddScope(const_String_or_char_ptr scope); +  virtual Hash* symbolScopeLookup(const_String_or_char_ptr scope); +  virtual Hash* symbolScopePseudoSymbolLookup(const_String_or_char_ptr scope); +  static Node *classLookup(const SwigType *s); /* Class lookup      */ +  static Node *enumLookup(SwigType *s);	/* Enum lookup       */ +  virtual int abstractClassTest(Node *n);	/* Is class really abstract? */ +  virtual int is_assignable(Node *n);	/* Is variable assignable? */ +  virtual String *runtimeCode();	/* returns the language specific runtime code */ +  virtual String *defaultExternalRuntimeFilename();	/* the default filename for the external runtime */ +  virtual void replaceSpecialVariables(String *method, String *tm, Parm *parm); /* Language specific special variable substitutions for $typemap() */ + +  /* Runtime is C++ based, so extern "C" header section */ +  void enable_cplus_runtime_mode(); + +  /* Returns the cplus_runtime mode */ +  int cplus_runtime_mode(); + +  /* Allow director related code generation */ +  void allow_directors(int val = 1); + +  /* Return true if directors are enabled */ +  int directorsEnabled() const; + +  /* Allow director protected members related code generation */ +  void allow_dirprot(int val = 1); + +  /* Allow all protected members code generation (for directors) */ +  void allow_allprotected(int val = 0); + +  /* Returns the dirprot mode */ +  int dirprot_mode() const; + +  /* Check if the non public constructor is  needed (for directors) */ +  int need_nonpublic_ctor(Node *n); + +  /* Check if the non public member is  needed (for directors) */ +  int need_nonpublic_member(Node *n); + +  /* Set none comparison string */ +  void setSubclassInstanceCheck(String *s); + +  /* Set overload variable templates argc and argv */ +  void setOverloadResolutionTemplates(String *argc, String *argv); + +  /* Language instance is a singleton - get instance */ +  static Language* instance(); + +protected: +  /* Allow multiple-input typemaps */ +  void allow_multiple_input(int val = 1); + +  /* Allow overloaded functions */ +  void allow_overloading(int val = 1); + +  /* Wrapping class query */ +  int is_wrapping_class() const; + +  /* Return the node for the current class */ +  Node *getCurrentClass() const; + +  /* Return C++ mode */ +  int getCPlusMode() const; + +  /* Return the namespace for the class/enum - the nspace feature */ +  String *getNSpace() const; + +  /* Return the real name of the current class */ +  String *getClassName() const; + +  /* Return the classes hash */ +  Hash *getClassHash() const; + +  /* Return the current class prefix */ +  String *getClassPrefix() const; + +  /* Return the current enum class prefix */ +  String *getEnumClassPrefix() const; + +  /* Fully qualified type name to use */ +  String *getClassType() const; + +  /* Return true if the current method is part of a smart-pointer */ +  int is_smart_pointer() const; + +  /* Return the name to use for the given parameter. */ +  virtual String *makeParameterName(Node *n, Parm *p, int arg_num, bool setter = false) const; + +  /* Some language modules require additional wrappers for virtual methods not declared in sub-classes */ +  virtual bool extraDirectorProtectedCPPMethodsRequired() const; + +public: +  enum NestedClassSupport { +    NCS_None, // Target language does not have an equivalent to nested classes +    NCS_Full, // Target language does have an equivalent to nested classes and is fully implemented +    NCS_Unknown // Target language may or may not have an equivalent to nested classes. If it does, it has not been implemented yet. +  }; +  /* Does target language support nested classes? Default is NCS_Unknown.  +    If NCS_Unknown is returned, then the nested classes will be ignored unless  +    %feature "flatnested" is applied to them, in which case they will appear in global space. +    If the target language does not support the notion of class +    nesting, the language module should return NCS_None from this function, and  +    the nested classes will be moved to the global scope (like implicit global %feature "flatnested"). +  */ +  virtual NestedClassSupport nestedClassesSupport() const; + +  /* Returns true if the target language supports key word arguments (kwargs) */ +  virtual bool kwargsSupport() const; + +protected: +  /* Identifies if a protected members that are generated when the allprotected option is used. +     This does not include protected virtual methods as they are turned on with the dirprot option. */ +  bool isNonVirtualProtectedAccess(Node *n) const; + +  /* Identify if a wrapped global or member variable n should use the naturalvar feature */ +  int use_naturalvar_mode(Node *n) const; + +  /* Director subclass comparison test */ +  String *none_comparison; + +  /* Director constructor "template" code */ +  String *director_ctor_code; + +  /* Director 'protected' constructor "template" code */ +  String *director_prot_ctor_code; + +  /* Director allows multiple inheritance */ +  int director_multiple_inheritance; + +  /* Director language module */ +  int director_language; + +  /* Used to translate Doxygen comments to target documentation format */ +  class DoxygenTranslator *doxygenTranslator; + +private: +  void unrollOneVirtualMethod(String *classname, Node *n, Node *parent, List *vm, int &virtual_destructor, int protectedbase); + +  Hash *symtabs; /* symbol tables */ +  int overloading; +  int multiinput; +  int cplus_runtime; +  int directors; +  static Language *this_; +}; + +extern "C" { +  void SWIG_typemap_lang(const char *); +  typedef Language *(*ModuleFactory) (void); +} + +enum Status {Disabled, Experimental, Supported}; + +struct TargetLanguageModule { +  const char *name; +  ModuleFactory fac; +  const char *help; +  Status status; +}; + +int SWIG_main(int argc, char *argv[], const TargetLanguageModule *tlm); +void emit_parameter_variables(ParmList *l, Wrapper *f); +void emit_return_variable(Node *n, SwigType *rt, Wrapper *f); +void SWIG_config_file(const_String_or_char_ptr ); +const String *SWIG_output_directory(); +void SWIG_config_cppext(const char *ext); +void Swig_print_xml(Node *obj, String *filename); + +/* get the list of generated files */ +List *SWIG_output_files(); + +void SWIG_library_directory(const char *); +int emit_num_arguments(ParmList *); +int emit_num_required(ParmList *); +int emit_isvarargs(ParmList *p); +bool emit_isvarargs_function(Node *n); +void emit_attach_parmmaps(ParmList *, Wrapper *f); +void emit_mark_varargs(ParmList *l); +String *emit_action(Node *n); +int emit_action_code(Node *n, String *wrappercode, String *action); +void Swig_overload_check(Node *n); +String *Swig_overload_dispatch(Node *n, const_String_or_char_ptr fmt, int *, const_String_or_char_ptr fmt_fastdispatch = 0); +String *Swig_overload_dispatch_cast(Node *n, const_String_or_char_ptr fmt, int *); +List *Swig_overload_rank(Node *n, bool script_lang_wrapping); +SwigType *cplus_value_type(SwigType *t); + +/* directors.cxx start */ +String *Swig_csuperclass_call(String *base, String *method, ParmList *l); +String *Swig_class_declaration(Node *n, String *name); +String *Swig_class_name(Node *n); +String *Swig_method_call(const_String_or_char_ptr name, ParmList *parms); +String *Swig_method_decl(SwigType *return_base_type, SwigType *decl, const_String_or_char_ptr id, List *args, int default_args); +String *Swig_director_declaration(Node *n); +void Swig_director_emit_dynamic_cast(Node *n, Wrapper *f); +void Swig_director_parms_fixup(ParmList *parms); +bool Swig_director_can_unwrap(Node *n); +/* directors.cxx end */ + +/* Utilities */ + +int is_public(Node *n); +int is_private(Node *n); +int is_protected(Node *n); +int is_member_director(Node *parentnode, Node *member); +int is_member_director(Node *member); +int is_non_virtual_protected_access(Node *n); /* Check if the non-virtual protected members are required (for directors) */ + +void Wrapper_virtual_elimination_mode_set(int); +void Wrapper_fast_dispatch_mode_set(int); +void Wrapper_cast_dispatch_mode_set(int); +void Wrapper_naturalvar_mode_set(int); + +void clean_overloaded(Node *n); + +extern "C" { +  const char *Swig_to_string(DOH *object, int count = -1); +  const char *Swig_to_string_with_location(DOH *object, int count = -1); +  void Swig_print(DOH *object, int count = -1); +  void Swig_print_with_location(DOH *object, int count = -1); +} + +void Swig_default_allocators(Node *n); +void Swig_process_types(Node *n); + +/* Contracts */ +void Swig_contracts(Node *n); +void Swig_contract_mode_set(int flag); +int Swig_contract_mode_get(); + +/* Nested classes */ +void Swig_nested_process_classes(Node *n); +void Swig_nested_name_unnamed_c_structs(Node *n); + +/* Interface feature */ +void Swig_interface_feature_enable(); +void Swig_interface_propagate_methods(Node *n); + +/* Miscellaneous */ +template <class T> class save_value { +  T _value; +  T& _value_ptr; +  save_value(const save_value&); +  save_value& operator=(const save_value&); + +public: +  save_value(T& value) : _value(value), _value_ptr(value) {} +  save_value(T& value, T new_val) : _value(value), _value_ptr(value) { value = new_val; } +  ~save_value() { _value_ptr = _value; } +}; + +#endif diff --git a/contrib/tools/swig/Source/Modules/tcl8.cxx b/contrib/tools/swig/Source/Modules/tcl8.cxx new file mode 100644 index 00000000000..975230e8495 --- /dev/null +++ b/contrib/tools/swig/Source/Modules/tcl8.cxx @@ -0,0 +1,1291 @@ +/* ----------------------------------------------------------------------------- + * This file is part of SWIG, which is licensed as a whole under version 3  + * (or any later version) of the GNU General Public License. Some additional + * terms also apply to certain portions of SWIG. The full details of the SWIG + * license and copyrights can be found in the LICENSE and COPYRIGHT files + * included with the SWIG source code as distributed by the SWIG developers + * and at https://www.swig.org/legal.html. + * + * tcl8.cxx + * + * Tcl8 language module for SWIG. + * ----------------------------------------------------------------------------- */ + +#include "swigmod.h" +#include "cparse.h" + +static const char *usage = "\ +Tcl 8 Options (available with -tcl8)\n\ +     -itcl           - Enable ITcl support\n\ +     -nosafe         - Leave out SafeInit module function.\n\ +     -prefix <name>  - Set a prefix <name> to be prepended to all names\n\ +     -namespace      - Build module into a Tcl 8 namespace\n\ +     -pkgversion     - Set package version\n\n"; + +static String *cmd_tab = 0;	/* Table of command names    */ +static String *var_tab = 0;	/* Table of global variables */ +static String *const_tab = 0;	/* Constant table            */ +static String *methods_tab = 0;	/* Methods table             */ +static String *attr_tab = 0;	/* Attribute table           */ +static String *prefix = 0; +static String *module = 0; +static int namespace_option = 0; +static String *init_name = 0; +static String *ns_name = 0; +static int have_constructor; +static String *constructor_name; +static int have_destructor; +static int have_base_classes; +static String *destructor_action = 0; +static String *version = (String *) "0.0"; +static String *class_name = 0; + +static int have_attributes; +static int have_methods; +static int nosafe = 0; + +static File *f_header = 0; +static File *f_wrappers = 0; +static File *f_init = 0; +static File *f_begin = 0; +static File *f_runtime = 0; + + +//  Itcl support +static int itcl = 0; +static File *f_shadow = 0; +static File *f_shadow_stubs = 0; + +static String *constructor = 0; +static String *destructor = 0; +static String *base_classes = 0; +static String *base_class_init = 0; +static String *methods = 0; +static String *imethods = 0; +static String *attributes = 0; +static String *attribute_traces = 0; +static String *iattribute_traces = 0; + + + +class TCL8:public Language { +public: + +  /* ------------------------------------------------------------ +   * TCL8::main() +   * ------------------------------------------------------------ */ + +  virtual void main(int argc, char *argv[]) { + +     SWIG_library_directory("tcl"); + +    for (int i = 1; i < argc; i++) { +      if (argv[i]) { +	if (strcmp(argv[i], "-prefix") == 0) { +	  if (argv[i + 1]) { +	    prefix = NewString(argv[i + 1]); +	    Swig_mark_arg(i); +	    Swig_mark_arg(i + 1); +	    i++; +	  } else +	     Swig_arg_error(); +	} else if (strcmp(argv[i], "-pkgversion") == 0) { +	  if (argv[i + 1]) { +	    version = NewString(argv[i + 1]); +	    Swig_mark_arg(i); +	    Swig_mark_arg(i + 1); +	    i++; +	  } +	} else if (strcmp(argv[i], "-namespace") == 0) { +	  namespace_option = 1; +	  Swig_mark_arg(i); +	} else if (strcmp(argv[i], "-itcl") == 0) { +	  itcl = 1; +	  Swig_mark_arg(i); +	} else if (strcmp(argv[i], "-nosafe") == 0) { +	  nosafe = 1; +	  Swig_mark_arg(i); +	} else if (strcmp(argv[i], "-help") == 0) { +	  fputs(usage, stdout); +	} else if (strcmp(argv[i], "-cppcast") == 0) { +	  Printf(stderr, "Deprecated command line option: %s. This option is now always on.\n", argv[i]); +	  Swig_mark_arg(i); +	} else if (strcmp(argv[i], "-nocppcast") == 0) { +	  Printf(stderr, "Deprecated command line option: %s. This option is no longer supported.\n", argv[i]); +	  Swig_mark_arg(i); +	  Exit(EXIT_FAILURE); +	} +      } +    } + +    Preprocessor_define("SWIGTCL 1", 0); +    // SWIGTCL8 is deprecated, and no longer documented. +    Preprocessor_define("SWIGTCL8 1", 0); +    SWIG_typemap_lang("tcl8"); +    SWIG_config_file("tcl8.swg"); +    allow_overloading(); +  } + +  /* ------------------------------------------------------------ +   * top() +   * ------------------------------------------------------------ */ + +  virtual int top(Node *n) { + +    /* Initialize all of the output files */ +    String *outfile = Getattr(n, "outfile"); + +    f_begin = NewFile(outfile, "w", SWIG_output_files()); +    if (!f_begin) { +      FileErrorDisplay(outfile); +      Exit(EXIT_FAILURE); +    } +    f_runtime = NewString(""); +    f_init = NewString(""); +    f_header = NewString(""); +    f_wrappers = NewString(""); + +    /* Register file targets with the SWIG file handler */ +    Swig_register_filebyname("header", f_header); +    Swig_register_filebyname("wrapper", f_wrappers); +    Swig_register_filebyname("begin", f_begin); +    Swig_register_filebyname("runtime", f_runtime); +    Swig_register_filebyname("init", f_init); + +    /* Initialize some variables for the object interface */ + +    cmd_tab = NewString(""); +    var_tab = NewString(""); +    methods_tab = NewString(""); +    const_tab = NewString(""); + +    Swig_banner(f_begin); + +    Swig_obligatory_macros(f_runtime, "TCL"); + +    /* Set the module name, namespace, and prefix */ + +    module = NewStringf("%(lower)s", Getattr(n, "name")); +    init_name = NewStringf("%(title)s_Init", module); + +    ns_name = prefix ? Copy(prefix) : Copy(module); +    if (prefix) +      Append(prefix, "_"); + + +    /* If shadow classing is enabled, we're going to change the module name to "_module" */ +    if (itcl) { +      String *filen; +      filen = NewStringf("%s%s.itcl", SWIG_output_directory(), module); + +      Insert(module, 0, "_"); + +      if ((f_shadow = NewFile(filen, "w", SWIG_output_files())) == 0) { +	FileErrorDisplay(filen); +	Exit(EXIT_FAILURE); +      } +      f_shadow_stubs = NewString(""); + +      Swig_register_filebyname("shadow", f_shadow); +      Swig_register_filebyname("itcl", f_shadow); + +      Swig_banner_target_lang(f_shadow, "#"); + +      Printv(f_shadow, "\npackage require Itcl\n\n", NIL); +      Delete(filen); +    } + +    /* Generate some macros used throughout code generation */ + +    Printf(f_header, "#define SWIG_init    %s\n", init_name); +    Printf(f_header, "#define SWIG_name    \"%s\"\n", module); +    if (namespace_option) { +      Printf(f_header, "#define SWIG_prefix  \"%s::\"\n", ns_name); +      Printf(f_header, "#define SWIG_namespace \"%s\"\n\n", ns_name); +    } else { +      Printf(f_header, "#define SWIG_prefix  \"%s\"\n", prefix); +    } +    Printf(f_header, "#define SWIG_version \"%s\"\n", version); + +    Printf(cmd_tab, "\nstatic swig_command_info swig_commands[] = {\n"); +    Printf(var_tab, "\nstatic swig_var_info swig_variables[] = {\n"); +    Printf(const_tab, "\nstatic swig_const_info swig_constants[] = {\n"); + +    Printf(f_wrappers, "#ifdef __cplusplus\nextern \"C\" {\n#endif\n"); + +    /* Start emitting code */ +    Language::top(n); + +    /* Done.  Close up the module */ +    Printv(cmd_tab, tab4, "{0, 0, 0}\n", "};\n", NIL); +    Printv(var_tab, tab4, "{0,0,0,0}\n", "};\n", NIL); +    Printv(const_tab, tab4, "{0,0,0,0,0,0}\n", "};\n", NIL); + +    Printv(f_wrappers, cmd_tab, var_tab, const_tab, NIL); + +    /* Dump the pointer equivalency table */ +    SwigType_emit_type_table(f_runtime, f_wrappers); + +    Printf(f_wrappers, "#ifdef __cplusplus\n}\n#endif\n"); + +    /* Close the init function and quit */ +    Printf(f_init, "return TCL_OK;\n}\n"); + +    if (!nosafe) { +      Printf(f_init, "SWIGEXPORT int %(title)s_SafeInit(Tcl_Interp *interp) {\n", module); +      Printf(f_init, "    return SWIG_init(interp);\n"); +      Printf(f_init, "}\n"); +    } + +    if (itcl) { +      Printv(f_shadow, f_shadow_stubs, "\n", NIL); +      Delete(f_shadow); +    } + +    /* Close all of the files */ +    Dump(f_runtime, f_begin); +    Printv(f_begin, f_header, f_wrappers, NIL); +    Wrapper_pretty_print(f_init, f_begin); +    Delete(f_header); +    Delete(f_wrappers); +    Delete(f_init); +    Delete(f_runtime); +    Delete(f_begin); +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * functionWrapper() +   * ------------------------------------------------------------ */ + +  virtual int functionWrapper(Node *n) { +    String *name = Getattr(n, "name");	/* Like to get rid of this */ +    String *iname = Getattr(n, "sym:name"); +    SwigType *type = Getattr(n, "type"); +    ParmList *parms = Getattr(n, "parms"); +    String *overname = 0; + +    Parm *p; +    int i; +    String *tm; +    Wrapper *f; +    String *incode, *cleanup, *outarg, *argstr, *args; +    int num_arguments = 0; +    int num_required = 0; +    int varargs = 0; + +    char source[64]; + +    if (Getattr(n, "sym:overloaded")) { +      overname = Getattr(n, "sym:overname"); +    } else { +      if (!addSymbol(iname, n)) +	return SWIG_ERROR; +    } + +    incode = NewString(""); +    cleanup = NewString(""); +    outarg = NewString(""); +    argstr = NewString("\""); +    args = NewString(""); + +    f = NewWrapper(); + +#ifdef SWIG_USE_RESULTOBJ +    Wrapper_add_local(f, "resultobj", "Tcl_Obj *resultobj = NULL"); +#endif + + +    String *wname = Swig_name_wrapper(iname); +    if (overname) { +      Append(wname, overname); +    } +    Setattr(n, "wrap:name", wname); + +    Printv(f->def, "SWIGINTERN int\n ", wname, "(ClientData clientData SWIGUNUSED, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {", NIL); + +    // Emit all of the local variables for holding arguments. +    emit_parameter_variables(parms, f); + +    /* Attach standard typemaps */ +    emit_attach_parmmaps(parms, f); +    Setattr(n, "wrap:parms", parms); + +    /* Get number of require and total arguments */ +    num_arguments = emit_num_arguments(parms); +    num_required = emit_num_required(parms); +    varargs = emit_isvarargs(parms); + +    /* Unmarshal parameters */ + +    for (i = 0, p = parms; i < num_arguments; i++) { +      /* Skip ignored arguments */ + +      while (checkAttribute(p, "tmap:in:numinputs", "0")) { +	p = Getattr(p, "tmap:in:next"); +      } + +      SwigType *pt = Getattr(p, "type"); +      String *ln = Getattr(p, "lname"); + +      /* Produce string representations of the source and target arguments */ +      sprintf(source, "objv[%d]", i + 1); + +      if (i == num_required) +	Putc('|', argstr); +      if ((tm = Getattr(p, "tmap:in"))) { +	String *parse = Getattr(p, "tmap:in:parse"); +	if (!parse) { +	  Replaceall(tm, "$input", source); +	  Setattr(p, "emit:input", source); + +	  if (Getattr(p, "wrap:disown") || (Getattr(p, "tmap:in:disown"))) { +	    Replaceall(tm, "$disown", "SWIG_POINTER_DISOWN"); +	  } else { +	    Replaceall(tm, "$disown", "0"); +	  } + +	  Putc('o', argstr); +	  Printf(args, ",(void *)0"); +	  if (i >= num_required) { +	    Printf(incode, "if (objc > %d) {\n", i + 1); +	  } +	  Printf(incode, "%s\n", tm); +	  if (i >= num_required) { +	    Printf(incode, "}\n"); +	  } +	} else { +	  Printf(argstr, "%s", parse); +	  Printf(args, ",&%s", ln); +	  if (Strcmp(parse, "p") == 0) { +	    SwigType *lt = SwigType_ltype(pt); +	    SwigType_remember(pt); +	    if (Cmp(lt, "p.void") == 0) { +	      Printf(args, ",(void *)0"); +	    } else { +	      Printf(args, ",SWIGTYPE%s", SwigType_manglestr(pt)); +	    } +	    Delete(lt); +	  } +	} +	p = Getattr(p, "tmap:in:next"); +	continue; +      } else { +	Swig_warning(WARN_TYPEMAP_IN_UNDEF, input_file, line_number, "Unable to use type %s as a function argument.\n", SwigType_str(pt, 0)); +      } +      p = nextSibling(p); +    } + +    if (!varargs) { +      Putc(':', argstr); +    } else { +      Putc(';', argstr); +      /* If variable length arguments we need to emit the in typemap here */ +      if (p && (tm = Getattr(p, "tmap:in"))) { +	sprintf(source, "objv[%d]", i + 1); +	Printf(incode, "if (objc > %d) {\n", i); +	Replaceall(tm, "$input", source); +	Printv(incode, tm, "\n", NIL); +	Printf(incode, "}\n"); +      } +    } + +    Printf(argstr, "%s\"", usage_string(Char(iname), type, parms)); + +    Printv(f->code, "if (SWIG_GetArgs(interp, objc, objv,", argstr, args, ") == TCL_ERROR) SWIG_fail;\n", NIL); + +    Printv(f->code, incode, NIL); + +    /* Insert constraint checking code */ +    for (p = parms; p;) { +      if ((tm = Getattr(p, "tmap:check"))) { +	Printv(f->code, tm, "\n", NIL); +	p = Getattr(p, "tmap:check:next"); +      } else { +	p = nextSibling(p); +      } +    } + +    /* Insert cleanup code */ +    for (i = 0, p = parms; p; i++) { +      if (!checkAttribute(p, "tmap:in:numinputs", "0") +	  && !Getattr(p, "tmap:in:parse") && (tm = Getattr(p, "tmap:freearg"))) { +	if (Len(tm) != 0) { +	  Printv(cleanup, tm, "\n", NIL); +	} +	p = Getattr(p, "tmap:freearg:next"); +      } else { +	p = nextSibling(p); +      } +    } + +    /* Insert argument output code */ +    for (i = 0, p = parms; p; i++) { +      if ((tm = Getattr(p, "tmap:argout"))) { +#ifdef SWIG_USE_RESULTOBJ +	Replaceall(tm, "$result", "resultobj"); +#else +	Replaceall(tm, "$result", "(Tcl_GetObjResult(interp))"); +#endif +	Replaceall(tm, "$arg", Getattr(p, "emit:input")); +	Replaceall(tm, "$input", Getattr(p, "emit:input")); +	Printv(outarg, tm, "\n", NIL); +	p = Getattr(p, "tmap:argout:next"); +      } else { +	p = nextSibling(p); +      } +    } + +    /* Now write code to make the function call */ +    String *actioncode = emit_action(n); + +    /* Need to redo all of this code (eventually) */ + +    /* Return value if necessary  */ +    if ((tm = Swig_typemap_lookup_out("out", n, Swig_cresult_name(), f, actioncode))) { +#ifdef SWIG_USE_RESULTOBJ +      Replaceall(tm, "$result", "resultobj"); +#else +      Replaceall(tm, "$result", "(Tcl_GetObjResult(interp))"); +#endif +      if (GetFlag(n, "feature:new")) { +	Replaceall(tm, "$owner", "SWIG_POINTER_OWN"); +      } else { +	Replaceall(tm, "$owner", "0"); +      } +      Printf(f->code, "%s\n", tm); +    } else { +      Swig_warning(WARN_TYPEMAP_OUT_UNDEF, input_file, line_number, "Unable to use return type %s in function %s.\n", SwigType_str(type, 0), name); +    } +    emit_return_variable(n, type, f); + +    /* Dump output argument code */ +    Printv(f->code, outarg, NIL); + +    /* Dump the argument cleanup code */ +    Printv(f->code, cleanup, NIL); + +    /* Look for any remaining cleanup */ +    if (GetFlag(n, "feature:new")) { +      if ((tm = Swig_typemap_lookup("newfree", n, Swig_cresult_name(), 0))) { +	Printf(f->code, "%s\n", tm); +      } +    } + +    if ((tm = Swig_typemap_lookup("ret", n, Swig_cresult_name(), 0))) { +      Printf(f->code, "%s\n", tm); +    } +#ifdef SWIG_USE_RESULTOBJ +    Printv(f->code, "if (resultobj) Tcl_SetObjResult(interp, resultobj);\n", NIL); +#endif +    Printv(f->code, "return TCL_OK;\n", NIL); +    Printv(f->code, "fail:\n", cleanup, "return TCL_ERROR;\n", NIL); +    Printv(f->code, "}\n", NIL); + +    /* Substitute the cleanup code */ +    Replaceall(f->code, "$cleanup", cleanup); +    Replaceall(f->code, "$symname", iname); + +    /* Dump out the function */ +    Wrapper_print(f, f_wrappers); + +    if (!Getattr(n, "sym:overloaded")) { +      /* Register the function with Tcl */ +      Printv(cmd_tab, tab4, "{ SWIG_prefix \"", iname, "\", (swig_wrapper_func) ", Swig_name_wrapper(iname), ", NULL},\n", NIL); +    } else { +      if (!Getattr(n, "sym:nextSibling")) { +	/* Emit overloading dispatch function */ + +	int maxargs; +	String *dispatch = Swig_overload_dispatch(n, "return %s(clientData, interp, objc, argv - 1);", &maxargs); + +	/* Generate a dispatch wrapper for all overloaded functions */ + +	Wrapper *df = NewWrapper(); +	String *dname = Swig_name_wrapper(iname); + +	Printv(df->def, "SWIGINTERN int\n", dname, "(ClientData clientData SWIGUNUSED, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {", NIL); +	Printf(df->code, "Tcl_Obj *CONST *argv = objv+1;\n"); +	Printf(df->code, "int argc = objc-1;\n"); +	Printv(df->code, dispatch, "\n", NIL); +	Node *sibl = n; +	while (Getattr(sibl, "sym:previousSibling")) +	  sibl = Getattr(sibl, "sym:previousSibling");	// go all the way up +	String *protoTypes = NewString(""); +	do { +	  String *fulldecl = Swig_name_decl(sibl); +	  Printf(protoTypes, "\n\"    %s\\n\"", fulldecl); +	  Delete(fulldecl); +	} while ((sibl = Getattr(sibl, "sym:nextSibling"))); +	Printf(df->code, "Tcl_SetResult(interp,(char *) " +	       "\"Wrong number or type of arguments for overloaded function '%s'.\\n\"" +	       "\n\"  Possible C/C++ prototypes are:\\n\"%s, TCL_STATIC);\n", iname, protoTypes); +	Delete(protoTypes); +	Printf(df->code, "return TCL_ERROR;\n"); +	Printv(df->code, "}\n", NIL); +	Wrapper_print(df, f_wrappers); +	Printv(cmd_tab, tab4, "{ SWIG_prefix \"", iname, "\", (swig_wrapper_func) ", dname, ", NULL},\n", NIL); +	DelWrapper(df); +	Delete(dispatch); +	Delete(dname); +      } +    } + +    Delete(incode); +    Delete(cleanup); +    Delete(outarg); +    Delete(argstr); +    Delete(args); +    DelWrapper(f); +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * variableWrapper() +   * ------------------------------------------------------------ */ + +  virtual int variableWrapper(Node *n) { + +    String *name = Getattr(n, "name"); +    String *iname = Getattr(n, "sym:name"); +    SwigType *t = Getattr(n, "type"); + +    String *setname = 0; +    String *setfname = 0; +    Wrapper *setf = 0, *getf = 0; +    int readonly = 0; +    String *tm; + +    if (!addSymbol(iname, n)) +      return SWIG_ERROR; + +    /* Create a function for getting a variable */ +    int addfail = 0; +    getf = NewWrapper(); +    String *getname = Swig_name_get(NSPACE_TODO, iname); +    String *getfname = Swig_name_wrapper(getname); +    Setattr(n, "wrap:name", getfname); +    Printv(getf->def, "SWIGINTERN const char *", getfname, "(ClientData clientData SWIGUNUSED, Tcl_Interp *interp, char *name1, char *name2, int flags) {", NIL); +    Wrapper_add_local(getf, "value", "Tcl_Obj *value = 0"); +    if ((tm = Swig_typemap_lookup("varout", n, name, 0))) { +      Replaceall(tm, "$result", "value"); +      /* Printf(getf->code, "%s\n",tm); */ +      addfail = emit_action_code(n, getf->code, tm); +      Printf(getf->code, "if (value) {\n"); +      Printf(getf->code, "Tcl_SetVar2(interp,name1,name2,Tcl_GetStringFromObj(value,NULL), flags);\n"); +      Printf(getf->code, "Tcl_DecrRefCount(value);\n"); +      Printf(getf->code, "}\n"); +      Printf(getf->code, "return NULL;\n"); +      if (addfail) { +	Append(getf->code, "fail:\n"); +	Printf(getf->code, "return \"%s\";\n", iname); +      } +      Printf(getf->code, "}\n"); +      Wrapper_print(getf, f_wrappers); +    } else { +      Swig_warning(WARN_TYPEMAP_VAROUT_UNDEF, input_file, line_number, "Unable to read variable of type %s\n", SwigType_str(t, 0)); +      DelWrapper(getf); +      return SWIG_NOWRAP; +    } +    DelWrapper(getf); + +    /* Try to create a function setting a variable */ +    if (is_assignable(n)) { +      setf = NewWrapper(); +      setname = Swig_name_set(NSPACE_TODO, iname); +      setfname = Swig_name_wrapper(setname); +      Setattr(n, "wrap:name", setfname); +      if (setf) { +        Printv(setf->def, "SWIGINTERN const char *", setfname, +	     "(ClientData clientData SWIGUNUSED, Tcl_Interp *interp, char *name1, char *name2 SWIGUNUSED, int flags) {", NIL); +        Wrapper_add_local(setf, "value", "Tcl_Obj *value = 0"); +        Wrapper_add_local(setf, "name1o", "Tcl_Obj *name1o = 0"); + +        if ((tm = Swig_typemap_lookup("varin", n, name, 0))) { +	  Replaceall(tm, "$input", "value"); +	  Printf(setf->code, "name1o = Tcl_NewStringObj(name1,-1);\n"); +	  Printf(setf->code, "value = Tcl_ObjGetVar2(interp, name1o, 0, flags);\n"); +	  Printf(setf->code, "Tcl_DecrRefCount(name1o);\n"); +	  Printf(setf->code, "if (!value) SWIG_fail;\n"); +	  /* Printf(setf->code,"%s\n", tm); */ +	  emit_action_code(n, setf->code, tm); +	  Printf(setf->code, "return NULL;\n"); +	  Printf(setf->code, "fail:\n"); +	  Printf(setf->code, "return \"%s\";\n", iname); +	  Printf(setf->code, "}\n"); +	  Wrapper_print(setf, f_wrappers); +        } else { +	  Swig_warning(WARN_TYPEMAP_VARIN_UNDEF, input_file, line_number, "Unable to set variable of type %s.\n", SwigType_str(t, 0)); +	  readonly = 1; +        } +      } +      DelWrapper(setf); +    } else { +      readonly = 1; +    } + + +    Printv(var_tab, tab4, "{ SWIG_prefix \"", iname, "\", 0, (swig_variable_func) ", getfname, ",", NIL); +    if (readonly) { +      static int readonlywrap = 0; +      if (!readonlywrap) { +	Wrapper *ro = NewWrapper(); +	Printf(ro->def, +	       "SWIGINTERN const char *swig_readonly(ClientData clientData SWIGUNUSED, Tcl_Interp *interp SWIGUNUSED, char *name1 SWIGUNUSED, char *name2 SWIGUNUSED, int flags SWIGUNUSED) {"); +	Printv(ro->code, "return \"Variable is read-only\";\n", "}\n", NIL); +	Wrapper_print(ro, f_wrappers); +	readonlywrap = 1; +	DelWrapper(ro); +      } +      Printf(var_tab, "(swig_variable_func) swig_readonly},\n"); +    } else { +      Printv(var_tab, "(swig_variable_func) ", setfname, "},\n", NIL); +    } +    Delete(getfname); +    Delete(setfname); +    Delete(setname); +    Delete(getname); +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * constantWrapper() +   * ------------------------------------------------------------ */ + +  virtual int constantWrapper(Node *n) { +    String *name = Getattr(n, "name"); +    String *iname = Getattr(n, "sym:name"); +    String *nsname = !namespace_option ? Copy(iname) : NewStringf("%s::%s", ns_name, iname); +    SwigType *type = Getattr(n, "type"); +    String *rawval = Getattr(n, "rawval"); +    String *value = rawval ? rawval : Getattr(n, "value"); +    String *tm; + +    if (!addSymbol(iname, n)) +      return SWIG_ERROR; +    if (namespace_option) +      Setattr(n, "sym:name", nsname); + +    /* Special hook for member pointer */ +    if (SwigType_type(type) == T_MPOINTER) { +      String *wname = Swig_name_wrapper(iname); +      Printf(f_wrappers, "static %s = %s;\n", SwigType_str(type, wname), value); +      value = Char(wname); +    } + +    if ((tm = Swig_typemap_lookup("consttab", n, name, 0))) { +      Replaceall(tm, "$value", value); +      Replaceall(tm, "$nsname", nsname); +      Printf(const_tab, "%s,\n", tm); +    } else if ((tm = Swig_typemap_lookup("constcode", n, name, 0))) { +      Replaceall(tm, "$value", value); +      Replaceall(tm, "$nsname", nsname); +      Printf(f_init, "%s\n", tm); +    } else { +      Delete(nsname); +      Swig_warning(WARN_TYPEMAP_CONST_UNDEF, input_file, line_number, "Unsupported constant value.\n"); +      return SWIG_NOWRAP; +    } +    Delete(nsname); +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * nativeWrapper() +   * ------------------------------------------------------------ */ + +  virtual int nativeWrapper(Node *n) { +    String *name = Getattr(n, "sym:name"); +    String *funcname = Getattr(n, "wrap:name"); +    if (!addSymbol(funcname, n)) +      return SWIG_ERROR; + +    Printf(f_init, "\t Tcl_CreateObjCommand(interp, SWIG_prefix \"%s\", (swig_wrapper_func) %s, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);\n", name, +	   funcname); +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * classHandler() +   * ------------------------------------------------------------ */ + +  virtual int classHandler(Node *n) { +    static Hash *emitted = NewHash(); +    String *mangled_classname = 0; +    String *real_classname = 0; + +    have_constructor = 0; +    have_destructor = 0; +    destructor_action = 0; +    constructor_name = 0; + +    if (itcl) { +      constructor = NewString(""); +      destructor = NewString(""); +      base_classes = NewString(""); +      base_class_init = NewString(""); +      methods = NewString(""); +      imethods = NewString(""); +      attributes = NewString(""); +      attribute_traces = NewString(""); +      iattribute_traces = NewString(""); + +      have_base_classes = 0; +      have_methods = 0; +      have_attributes = 0; +    } + +    class_name = Getattr(n, "sym:name"); +    if (!addSymbol(class_name, n)) +      return SWIG_ERROR; + +    real_classname = Getattr(n, "name"); +    mangled_classname = Swig_name_mangle(real_classname); + +    if (Getattr(emitted, mangled_classname)) +      return SWIG_NOWRAP; +    Setattr(emitted, mangled_classname, "1"); + +    attr_tab = NewString(""); +    Printf(attr_tab, "static swig_attribute swig_"); +    Printv(attr_tab, mangled_classname, "_attributes[] = {\n", NIL); + +    methods_tab = NewStringf(""); +    Printf(methods_tab, "static swig_method swig_"); +    Printv(methods_tab, mangled_classname, "_methods[] = {\n", NIL); + +    /* Generate normal wrappers */ +    Language::classHandler(n); + +    SwigType *t = Copy(Getattr(n, "name")); +    SwigType_add_pointer(t); + +    // Catch all: eg. a class with only static functions and/or variables will not have 'remembered' +    // SwigType_remember(t); +    String *wrap_class = NewStringf("&_wrap_class_%s", mangled_classname); +    SwigType_remember_clientdata(t, wrap_class); + +    String *rt = Copy(getClassType()); +    SwigType_add_pointer(rt); + +    // Register the class structure with the type checker +    /*    Printf(f_init,"SWIG_TypeClientData(SWIGTYPE%s, (void *) &_wrap_class_%s);\n", SwigType_manglestr(t), mangled_classname); */ +    if (have_destructor) { +      Printv(f_wrappers, "SWIGINTERN void swig_delete_", class_name, "(void *obj) {\n", NIL); +      if (destructor_action) { +	Printv(f_wrappers, SwigType_str(rt, "arg1"), " = (", SwigType_str(rt, 0), ") obj;\n", NIL); +	Printv(f_wrappers, destructor_action, "\n", NIL); +      } else { +	if (CPlusPlus) { +	  Printv(f_wrappers, "    delete (", SwigType_str(rt, 0), ") obj;\n", NIL); +	} else { +	  Printv(f_wrappers, "    free((char *) obj);\n", NIL); +	} +      } +      Printf(f_wrappers, "}\n"); +    } + +    Printf(methods_tab, "    {0,0}\n};\n"); +    Printv(f_wrappers, methods_tab, NIL); + +    Printf(attr_tab, "    {0,0,0}\n};\n"); +    Printv(f_wrappers, attr_tab, NIL); + +    /* Handle inheritance */ + +    String *base_class = NewString(""); +    String *base_class_names = NewString(""); + +    if (itcl) { +      base_classes = NewString(""); +    } + +    List *baselist = Getattr(n, "bases"); +    if (baselist && Len(baselist)) { +      Iterator b; +      int index = 0; +      b = First(baselist); +      while (b.item) { +	String *bname = Getattr(b.item, "name"); +	if ((!bname) || GetFlag(b.item, "feature:ignore") || (!Getattr(b.item, "module"))) { +	  b = Next(b); +	  continue; +	} +	if (itcl) { +	  have_base_classes = 1; +	  Printv(base_classes, bname, " ", NIL); +	  Printv(base_class_init, "    ", bname, "Ptr::constructor $ptr\n", NIL); +	} +	String *bmangle = Swig_name_mangle(bname); +	//      Printv(f_wrappers,"extern swig_class _wrap_class_", bmangle, ";\n", NIL); +	//      Printf(base_class,"&_wrap_class_%s",bmangle); +	Printf(base_class, "0"); +	Printf(base_class_names, "\"%s *\",", SwigType_namestr(bname)); +	/* Put code to register base classes in init function */ + +	//Printf(f_init,"/* Register base : %s */\n", bmangle); +	//Printf(f_init,"swig_%s_bases[%d] = (swig_class *) SWIG_TypeQuery(\"%s *\")->clientdata;\n",  mangled_classname, index, SwigType_namestr(bname)); +	(void)index; +	b = Next(b); +	index++; +	Putc(',', base_class); +	Delete(bmangle); +      } +    } + +    if (itcl) { +      String *ptrclass = NewString(""); + +      // First, build the pointer base class +      Printv(ptrclass, "itcl::class ", class_name, "Ptr {\n", NIL); +      if (have_base_classes) +	Printv(ptrclass, "  inherit ", base_classes, "\n", NIL); + +      //  Define protected variables for SWIG object pointer +      Printv(ptrclass, "  protected variable swigobj\n", "  protected variable thisown\n", NIL); + +      //  Define public variables +      if (have_attributes) { +	Printv(ptrclass, attributes, NIL); + +	// base class swig_getset was being called for complex inheritance trees +	if (namespace_option) { + +	  Printv(ptrclass, "  protected method ", class_name, "_swig_getset {var name1 name2 op} {\n", NIL); + +	  Printv(ptrclass, +		 "    switch -exact -- $op {\n", +		 "      r {set $var [", ns_name, "::", class_name, "_[set var]_get $swigobj]}\n", +		 "      w {", ns_name, "::", class_name, "_${var}_set $swigobj [set $var]}\n", "    }\n", "  }\n", NIL); +	} else { +	  Printv(ptrclass, +		 "  protected method ", class_name, "_swig_getset {var name1 name2 op} {\n", +		 "    switch -exact -- $op {\n", +		 "      r {set $var [", class_name, "_[set var]_get $swigobj]}\n", +		 "      w {", class_name, "_${var}_set $swigobj [set $var]}\n", "    }\n", "  }\n", NIL); +	} +      } +      //  Add the constructor, which may include +      //  calls to base class class constructors + +      Printv(ptrclass, "  constructor { ptr } {\n", NIL); +      if (have_base_classes) { +	Printv(ptrclass, base_class_init, NIL); +	Printv(ptrclass, "  } {\n", NIL); +      } + +      Printv(ptrclass, "    set swigobj $ptr\n", "    set thisown 0\n", NIL); + +      if (have_attributes) { +	Printv(ptrclass, attribute_traces, NIL); +      } +      Printv(ptrclass, "  }\n", NIL); + + +      //  Add destructor +      Printv(ptrclass, "  destructor {\n", +	     "    set d_func delete_", class_name, "\n", +	     "    if { $thisown && ([info command $d_func] != \"\") } {\n" "      $d_func $swigobj\n", "    }\n", "  }\n", NIL); + +      //  Add methods +      if (have_methods) { +	Printv(ptrclass, imethods, NIL); +      } + +      //  Close out the pointer class +      Printv(ptrclass, "}\n\n", NIL); +      Printv(f_shadow, ptrclass, NIL); +      // pointer class end + + +      //  Create the "real" class. +      Printv(f_shadow, "itcl::class ", class_name, " {\n", NIL); +      Printv(f_shadow, "  inherit ", class_name, "Ptr\n", NIL); + +      //  If we have a constructor, then use it. +      //  If not, then we must have an abstract class without +      //  any constructor.  So we create a class constructor +      //  which will fail for this class (but not for inherited +      //  classes).  Note that the constructor must fail before +      //  calling the ptrclass constructor. + +      if (have_constructor) { +	Printv(f_shadow, constructor, NIL); +      } else { +	Printv(f_shadow, "  constructor { } {\n", NIL); +	Printv(f_shadow, "    # This constructor will fail if called directly\n", NIL); +	Printv(f_shadow, "    if { [info class] == \"::", class_name, "\" } {\n", NIL); +	Printv(f_shadow, "      error \"No constructor for class ", class_name, (Getattr(n, "abstracts") ? " - class is abstract" : ""), "\"\n", NIL); +	Printv(f_shadow, "    }\n", NIL); +	Printv(f_shadow, "  }\n", NIL); +      } + +      Printv(f_shadow, "}\n\n", NIL); +    } + +    Printv(f_wrappers, "static swig_class *swig_", mangled_classname, "_bases[] = {", base_class, "0};\n", NIL); +    Printv(f_wrappers, "static const char * swig_", mangled_classname, "_base_names[] = {", base_class_names, "0};\n", NIL); +    Delete(base_class); +    Delete(base_class_names); + +    Printv(f_wrappers, "static swig_class _wrap_class_", mangled_classname, " = { \"", class_name, "\", &SWIGTYPE", SwigType_manglestr(t), ",", NIL); + +    if (have_constructor) { +      Printf(f_wrappers, "%s", Swig_name_wrapper(Swig_name_construct(NSPACE_TODO, constructor_name))); +      Delete(constructor_name); +      constructor_name = 0; +    } else { +      Printf(f_wrappers, "0"); +    } +    if (have_destructor) { +      Printv(f_wrappers, ", swig_delete_", class_name, NIL); +    } else { +      Printf(f_wrappers, ",0"); +    } +    Printv(f_wrappers, ", swig_", mangled_classname, "_methods, swig_", mangled_classname, "_attributes, swig_", mangled_classname, "_bases,", +	   "swig_", mangled_classname, "_base_names, &swig_module, SWIG_TCL_HASHTABLE_INIT };\n", NIL); + +    if (!itcl) { +      Printv(cmd_tab, tab4, "{ SWIG_prefix \"", class_name, "\", (swig_wrapper_func) SWIG_ObjectConstructor, (ClientData)&_wrap_class_", mangled_classname, +	     "},\n", NIL); +    } + +    Delete(t); +    Delete(mangled_classname); +    return SWIG_OK; +  } + + +  /* ------------------------------------------------------------ +   * memberfunctionHandler() +   * ------------------------------------------------------------ */ + +  virtual int memberfunctionHandler(Node *n) { +    String *name = Getattr(n, "name"); +    String *iname = GetChar(n, "sym:name"); + +    String *realname, *rname; + +    Language::memberfunctionHandler(n); + +    realname = iname ? iname : name; +    rname = Swig_name_wrapper(Swig_name_member(NSPACE_TODO, class_name, realname)); +    if (!Getattr(n, "sym:nextSibling")) { +      Printv(methods_tab, tab4, "{\"", realname, "\", ", rname, "}, \n", NIL); +    } + +    if (itcl) { +      ParmList *l = Getattr(n, "parms"); +      Parm *p = 0; +      String *pname = NewString(""); + +      // Add this member to our class handler function +      Printv(imethods, tab2, "method ", realname, " [list ", NIL); + +      int pnum = 0; +      for (p = l; p; p = nextSibling(p)) { + +	String *pn = Getattr(p, "name"); +	String *dv = Getattr(p, "value"); +	SwigType *pt = Getattr(p, "type"); + +	Printv(pname, ",(", pt, ")", NIL); +	Clear(pname); + +	/* Only print an argument if not void */ +	if (Cmp(pt, "void") != 0) { +	  if (Len(pn) > 0) { +	    Printv(pname, pn, NIL); +	  } else { +	    Printf(pname, "p%d", pnum); +	  } + +	  if (Len(dv) > 0) { +	    String *defval = NewString(dv); +	    if (namespace_option) { +	      Insert(defval, 0, "::"); +	      Insert(defval, 0, ns_name); +	    } +	    if (Strncmp(dv, "(", 1) == 0) { +	      Insert(defval, 0, "$"); +	      Replaceall(defval, "(", ""); +	      Replaceall(defval, ")", ""); +	    } +	    Printv(imethods, "[list ", pname, " ", defval, "] ", NIL); +	  } else { +	    Printv(imethods, pname, " ", NIL); +	  } +	} +	++pnum; +      } +      Printv(imethods, "] ", NIL); + +      if (namespace_option) { +	Printv(imethods, "{ ", ns_name, "::", class_name, "_", realname, " $swigobj", NIL); +      } else { +	Printv(imethods, "{ ", class_name, "_", realname, " $swigobj", NIL); +      } + +      pnum = 0; +      for (p = l; p; p = nextSibling(p)) { + +	String *pn = Getattr(p, "name"); +	SwigType *pt = Getattr(p, "type"); +	Clear(pname); + +	/* Only print an argument if not void */ +	if (Cmp(pt, "void") != 0) { +	  if (Len(pn) > 0) { +	    Printv(pname, pn, NIL); +	  } else { +	    Printf(pname, "p%d", pnum); +	  } +	  Printv(imethods, " $", pname, NIL); +	} +	++pnum; +      } +      Printv(imethods, " }\n", NIL); +      have_methods = 1; +    } + +    Delete(rname); +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * membervariableHandler() +   * ------------------------------------------------------------ */ + +  virtual int membervariableHandler(Node *n) { +    String *symname = Getattr(n, "sym:name"); +    String *rname; + +    Language::membervariableHandler(n); +    Printv(attr_tab, tab4, "{ \"-", symname, "\",", NIL); +    rname = Swig_name_wrapper(Swig_name_get(NSPACE_TODO, Swig_name_member(NSPACE_TODO, class_name, symname))); +    Printv(attr_tab, rname, ", ", NIL); +    Delete(rname); +    if (!GetFlag(n, "feature:immutable")) { +      rname = Swig_name_wrapper(Swig_name_set(NSPACE_TODO, Swig_name_member(NSPACE_TODO, class_name, symname))); +      Printv(attr_tab, rname, "},\n", NIL); +      Delete(rname); +    } else { +      Printf(attr_tab, "0 },\n"); +    } + +    if (itcl) { +      Printv(attributes, "  public variable ", symname, "\n", NIL); + +      Printv(attribute_traces, "    trace variable ", symname, " rw [list ", class_name, "_swig_getset ", symname, "]\n", NIL); +      Printv(attribute_traces, "    set ", symname, "\n", NIL); + +      have_attributes = 1; +    } +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * constructorHandler() +   * ------------------------------------------------------------ */ + +  virtual int constructorHandler(Node *n) { +    Language::constructorHandler(n); + +    if (itcl) { +      String *name = Getattr(n, "name"); +      String *iname = GetChar(n, "sym:name"); + +      String *realname; + +      ParmList *l = Getattr(n, "parms"); +      Parm *p = 0; + +      String *pname = NewString(""); + +      realname = iname ? iname : name; + +      if (!have_constructor) { +	// Add this member to our class handler function +	Printf(constructor, "  constructor { "); + +	//  Add parameter list +	int pnum = 0; +	for (p = l; p; p = nextSibling(p)) { + +	  SwigType *pt = Getattr(p, "type"); +	  String *pn = Getattr(p, "name"); +	  String *dv = Getattr(p, "value"); +	  Clear(pname); + +	  /* Only print an argument if not void */ +	  if (Cmp(pt, "void") != 0) { +	    if (Len(pn) > 0) { +	      Printv(pname, pn, NIL); +	    } else { +	      Printf(pname, "p%d", pnum); +	    } + +	    if (Len(dv) > 0) { +	      Printv(constructor, "{", pname, " {", dv, "} } ", NIL); +	    } else { +	      Printv(constructor, pname, " ", NIL); +	    } +	  } +	  ++pnum; +	} +	Printf(constructor, "} { \n"); + +	// [BRE] 08/17/00 Added test to see if we are instantiating this object +	// type, or, if this constructor is being called as part of the itcl +	// inheritance hierarchy. +	// In the former case, we need to call the C++ constructor, in the +	// latter we don't, or we end up with two C++ objects. +	// Check to see if we are instantiating a 'realname' or something  +	// derived from it. +	// +	Printv(constructor, "    if { [string equal -nocase \"", realname, "\" \"[namespace tail [info class]]\" ] } {\n", NIL); + +	// Call to constructor wrapper and parent Ptr class +	// [BRE] add -namespace/-prefix support + +	if (namespace_option) { +	  Printv(constructor, "      ", realname, "Ptr::constructor [", ns_name, "::new_", realname, NIL); +	} else { +	  Printv(constructor, "      ", realname, "Ptr::constructor [new_", realname, NIL); +	} + +	pnum = 0; +	for (p = l; p; p = nextSibling(p)) { + +	  SwigType *pt = Getattr(p, "type"); +	  String *pn = Getattr(p, "name"); +	  Clear(pname); + +	  /* Only print an argument if not void */ +	  if (Cmp(pt, "void") != 0) { +	    if (Len(pn) > 0) { +	      Printv(pname, pn, NIL); +	    } else { +	      Printf(pname, "p%d", pnum); +	    } +	    Printv(constructor, " $", pname, NIL); +	  } +	  ++pnum; +	} + +	Printv(constructor, "]\n", "    }\n", "  } {\n", "    set thisown 1\n", "  }\n", NIL); +      } +    } + +    if (!have_constructor) +      constructor_name = NewString(Getattr(n, "sym:name")); +    have_constructor = 1; +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * destructorHandler() +   * ------------------------------------------------------------ */ + +  virtual int destructorHandler(Node *n) { +    Language::destructorHandler(n); +    have_destructor = 1; +    destructor_action = Getattr(n, "wrap:action"); +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * validIdentifier() +   * ------------------------------------------------------------ */ + +  virtual int validIdentifier(String *s) { +    if (Strchr(s, ' ')) +      return 0; +    return 1; +  } + +  /* ------------------------------------------------------------ +   * usage_string() +   * ------------------------------------------------------------ */ + +  char *usage_string(char *iname, SwigType *, ParmList *l) { +    static String *temp = 0; +    Parm *p; +    int i, numopt, pcount; + +    if (!temp) +      temp = NewString(""); +    Clear(temp); +    if (namespace_option) { +      Printf(temp, "%s::%s ", ns_name, iname); +    } else { +      Printf(temp, "%s ", iname); +    } +    /* Now go through and print parameters */ +    i = 0; +    pcount = emit_num_arguments(l); +    numopt = pcount - emit_num_required(l); +    for (p = l; p; p = nextSibling(p)) { + +      SwigType *pt = Getattr(p, "type"); +      String *pn = Getattr(p, "name"); +      /* Only print an argument if not ignored */ +      if (!checkAttribute(p, "tmap:in:numinputs", "0")) { +	if (i >= (pcount - numopt)) +	  Putc('?', temp); +	if (Len(pn) > 0) { +	  Printf(temp, "%s", pn); +	} else { +	  Printf(temp, "%s", SwigType_str(pt, 0)); +	} +	if (i >= (pcount - numopt)) +	  Putc('?', temp); +	Putc(' ', temp); +	i++; +      } +    } +    return Char(temp); +  } + +  String *runtimeCode() { +    String *s = NewString(""); +    String *serrors = Swig_include_sys("tclerrors.swg"); +    if (!serrors) { +      Printf(stderr, "*** Unable to open 'tclerrors.swg'\n"); +    } else { +      Append(s, serrors); +      Delete(serrors); +    } +    String *sapi = Swig_include_sys("tclapi.swg"); +    if (!sapi) { +      Printf(stderr, "*** Unable to open 'tclapi.swg'\n"); +    } else { +      Append(s, sapi); +      Delete(sapi); +    } +    String *srun = Swig_include_sys("tclrun.swg"); +    if (!srun) { +      Printf(stderr, "*** Unable to open 'tclrun.swg'\n"); +    } else { +      Append(s, srun); +      Delete(srun); +    } + +    return s; +  } + +  String *defaultExternalRuntimeFilename() { +    return NewString("swigtclrun.h"); +  } +}; + +/* ---------------------------------------------------------------------- + * swig_tcl()    - Instantiate module + * ---------------------------------------------------------------------- */ + +static Language *new_swig_tcl() { +  return new TCL8(); +} +extern "C" Language *swig_tcl(void) { +  return new_swig_tcl(); +} diff --git a/contrib/tools/swig/Source/Modules/typepass.cxx b/contrib/tools/swig/Source/Modules/typepass.cxx new file mode 100644 index 00000000000..2a1dadf735d --- /dev/null +++ b/contrib/tools/swig/Source/Modules/typepass.cxx @@ -0,0 +1,1322 @@ +/* -----------------------------------------------------------------------------  + * This file is part of SWIG, which is licensed as a whole under version 3  + * (or any later version) of the GNU General Public License. Some additional + * terms also apply to certain portions of SWIG. The full details of the SWIG + * license and copyrights can be found in the LICENSE and COPYRIGHT files + * included with the SWIG source code as distributed by the SWIG developers + * and at https://www.swig.org/legal.html. + * + * typepass.cxx + * + * This module builds all of the internal type information by collecting + * typedef declarations as well as registering classes, structures, and unions. + * This information is needed to correctly handle shadow classes and other + * advanced features.   This phase of compilation is also used to perform + * type-expansion.  All types are fully qualified with namespace prefixes + * and other information needed for compilation. + * ----------------------------------------------------------------------------- */ + +#include "swigmod.h" +#include "cparse.h" + +struct normal_node { +  Symtab *symtab; +  Hash *typescope; +  List *normallist; +  normal_node *next; +}; + +static normal_node *patch_list = 0; + +/* Singleton class - all non-static methods in this class are private */ +class TypePass:private Dispatcher { +  Node *inclass; +  Node *module; +  int importmode; +  String *nsname; +  String *nssymname; +  Hash *classhash; +  List *normalize; + +  TypePass() : +    inclass(0), +    module(0), +    importmode(0), +    nsname(0), +    nssymname(0), +    classhash(0), +    normalize(0) { +  } + +  /* Normalize a type. Replaces type with fully qualified version */ +  void normalize_type(SwigType *ty) { +    SwigType *qty; +    if (CPlusPlus) { +      Replaceall(ty, "struct ", ""); +      Replaceall(ty, "union ", ""); +      Replaceall(ty, "class ", ""); +    } + +    qty = SwigType_typedef_qualified(ty); +    /*    Printf(stdout,"%s --> %s\n", ty, qty); */ +    Clear(ty); +    Append(ty, qty); +    Delete(qty); +  } + +  /* Normalize a parameter list */ + +  void normalize_parms(ParmList *p) { +    while (p) { +      SwigType *ty = Getattr(p, "type"); +      normalize_type(ty); +      /* This is a check for a function type */ +      { +	SwigType *qty = SwigType_typedef_resolve_all(ty); +	if (SwigType_isfunction(qty)) { +	  SwigType_add_pointer(ty); +	} +	Delete(qty); +      } + +      String *value = Getattr(p, "value"); +      if (value) { +	Node *n = Swig_symbol_clookup(value, 0); +	if (n) { +	  String *q = Swig_symbol_qualified(n); +	  if (q && Len(q)) { +	    String *vb = Swig_scopename_last(value); +	    Clear(value); +	    Printf(value, "%s::%s", SwigType_namestr(q), vb); +	    Delete(q); +	  } +	} +      } +      if (value && SwigType_istemplate(value)) { +	String *nv = SwigType_namestr(value); +	Setattr(p, "value", nv); +      } +      p = nextSibling(p); +    } +  } + +  void normalize_later(ParmList *p) { +    while (p) { +      SwigType *ty = Getattr(p, "type"); +      Append(normalize, ty); +      p = nextSibling(p); +    } +  } + +  /* Walk through entries in normalize list and patch them up */ +  void normalize_list() { +    Hash *currentsym = Swig_symbol_current(); + +    normal_node *nn = patch_list; +    normal_node *np; +    while (nn) { +      Swig_symbol_setscope(nn->symtab); +      SwigType_set_scope(nn->typescope); +      Iterator t; +      for (t = First(nn->normallist); t.item; t = Next(t)) { +	normalize_type(t.item); +      } +      Delete(nn->normallist); +      np = nn->next; +      delete(nn); +      nn = np; +    } +    Swig_symbol_setscope(currentsym); +  } + +  /* generate C++ inheritance type-relationships */ +  void cplus_inherit_types_impl(Node *first, Node *cls, String *clsname, const char *bases, const char *baselist, int ispublic, String *cast = 0) { + +    if (first == cls) +      return;			/* The Marcelo check */ +    if (!cls) +      cls = first; +    List *alist = 0; +    List *ilist = Getattr(cls, bases); +    if (!ilist) { +      List *nlist = Getattr(cls, baselist); +      if (nlist) { +	int len = Len(nlist); +	int i; +	for (i = 0; i < len; i++) { +	  Node *bcls = 0; +	  int clsforward = 0; +	  String *bname = Getitem(nlist, i); +	  String *sname = bname; +	  String *tname = 0; + +	  /* Try to locate the base class.   We look in the symbol table and we chase  +	     typedef declarations to get to the base class if necessary */ +	  Symtab *st = Getattr(cls, "sym:symtab"); + +	  if (SwigType_istemplate(bname)) { +	    tname = SwigType_typedef_resolve_all(bname); +	    sname = tname; +	  } +	  while (1) { +	    String *qsname = SwigType_typedef_qualified(sname); +	    bcls = Swig_symbol_clookup(qsname, st); +	    Delete(qsname); +	    if (bcls) { +	      if (Strcmp(nodeType(bcls), "class") != 0) { +		/* Not a class.   The symbol could be a typedef. */ +		if (checkAttribute(bcls, "storage", "typedef")) { +		  SwigType *decl = Getattr(bcls, "decl"); +		  if (!decl || !(Len(decl))) { +		    sname = Getattr(bcls, "type"); +		    st = Getattr(bcls, "sym:symtab"); +		    if (SwigType_istemplate(sname)) { +		      if (tname) +			Delete(tname); +		      tname = SwigType_typedef_resolve_all(sname); +		      sname = tname; +		    } +		    continue; +		  } +		  // A case when both outer and nested classes inherit from the same parent. Constructor may be found instead of the class itself. +		} else if (GetFlag(cls, "nested") && checkAttribute(bcls, "nodeType", "constructor")) { +		  bcls = Getattr(bcls, "parentNode"); +		  if (Getattr(bcls, "typepass:visit")) { +		    if (!Getattr(bcls, "feature:onlychildren")) { +		      if (!ilist) +			ilist = alist = NewList(); +		      Append(ilist, bcls); +		    } else { +		      if (!GetFlag(bcls, "feature:ignore")) { +			Swig_warning(WARN_TYPE_UNDEFINED_CLASS, Getfile(bname), Getline(bname), "Base class '%s' has no name as it is an empty template instantiated with '%%template()'. Ignored.\n", SwigType_namestr(bname)); +			Swig_warning(WARN_TYPE_UNDEFINED_CLASS, Getfile(bcls), Getline(bcls), "The %%template directive must be written before '%s' is used as a base class and be declared with a name.\n", SwigType_namestr(bname)); +		      } +		    } +		  } +		  break; +		} +		if (Strcmp(nodeType(bcls), "classforward") != 0) { +		  Swig_error(Getfile(bname), Getline(bname), "'%s' is not a valid base class.\n", SwigType_namestr(bname)); +		  Swig_error(Getfile(bcls), Getline(bcls), "See definition of '%s'.\n", SwigType_namestr(bname)); +		} else { +		  Swig_warning(WARN_TYPE_INCOMPLETE, Getfile(bname), Getline(bname), "Base class '%s' is incomplete.\n", SwigType_namestr(bname)); +		  Swig_warning(WARN_TYPE_INCOMPLETE, Getfile(bcls), Getline(bcls), "Only forward declaration '%s' was found.\n", SwigType_namestr(bname)); +		  clsforward = 1; +		} +		bcls = 0; +	      } else { +		if (Getattr(bcls, "typepass:visit")) { +		  if (!Getattr(bcls, "feature:onlychildren")) { +		    if (!ilist) +		      ilist = alist = NewList(); +		    Append(ilist, bcls); +		  } else { +		    if (!GetFlag(bcls, "feature:ignore")) { +		      Swig_warning(WARN_TYPE_UNDEFINED_CLASS, Getfile(bname), Getline(bname), "Base class '%s' has no name as it is an empty template instantiated with '%%template()'. Ignored.\n", SwigType_namestr(bname)); +		      Swig_warning(WARN_TYPE_UNDEFINED_CLASS, Getfile(bcls), Getline(bcls), "The %%template directive must be written before '%s' is used as a base class and be declared with a name.\n", SwigType_namestr(bname)); +		    } +		  } +		} else { +		  Swig_warning(WARN_TYPE_UNDEFINED_CLASS, Getfile(bname), Getline(bname), "Base class '%s' undefined.\n", SwigType_namestr(bname)); +		  Swig_warning(WARN_TYPE_UNDEFINED_CLASS, Getfile(bcls), Getline(bcls), "'%s' must be defined before it is used as a base class.\n", SwigType_namestr(bname)); +		} +	      } +	    } +	    break; +	  } + +	  if (tname) +	    Delete(tname); +	  if (!bcls) { +	    if (!clsforward && !GetFlag(cls, "feature:ignore")) { +	      if (ispublic && !Getmeta(bname, "already_warned")) { +		Swig_warning(WARN_TYPE_UNDEFINED_CLASS, Getfile(bname), Getline(bname), "Nothing known about base class '%s'. Ignored.\n", SwigType_namestr(bname)); +		if (Strchr(bname, '<')) { +		  Swig_warning(WARN_TYPE_UNDEFINED_CLASS, Getfile(bname), Getline(bname), "Maybe you forgot to instantiate '%s' using %%template.\n", SwigType_namestr(bname)); +		} +		Setmeta(bname, "already_warned", "1"); +	      } +	    } +	    SwigType_inherit(clsname, bname, cast, 0); +	  } +	} +      } +      if (ilist) { +	Setattr(cls, bases, ilist); +      } +    } +    if (alist) +      Delete(alist); + +    if (!ilist) +      return; +    int len = Len(ilist); +    int i; +    for (i = 0; i < len; i++) { +      Node *n = Getitem(ilist, i); +      String *bname = Getattr(n, "name"); +      Node *bclass = n;		/* Getattr(n,"class"); */ +      Hash *scopes = Getattr(bclass, "typescope"); +      SwigType_inherit(clsname, bname, cast, 0); +      if (ispublic && !GetFlag(bclass, "feature:ignore")) { +	String *smartptr = Getattr(first, "feature:smartptr"); +	if (smartptr) { +	  SwigType *smart = Swig_cparse_smartptr(first); +	  if (smart) { +	    /* Record a (fake) inheritance relationship between smart pointer +	       and smart pointer to base class, so that smart pointer upcasts +	       are automatically generated. */ +	    SwigType *bsmart = Copy(smart); + +	    // TODO: SwigType_typedef_resolve_all on a String instead of SwigType is incorrect for templates +	    SwigType *rclsname = SwigType_typedef_resolve_all(clsname); +	    SwigType *rbname = SwigType_typedef_resolve_all(bname); +	    int replace_count = Replaceall(bsmart, rclsname, rbname); +	    if (replace_count == 0) { +	      // If no replacement made, it will be because rclsname is fully resolved, but the +	      // type in the smartptr feature used a typedef or not fully resolved name. +	      String *firstname = Getattr(first, "name"); +	      Replaceall(bsmart, firstname, rbname); +	    } +	    // The code above currently creates a smartptr of the base class by substitution, replacing Derived +	    // with Base resulting in something like: 'smartptr< Derived >' from 'smartptr< Base >'. Instead +	    // the feature:smartptr should be used as it also contains 'smartptr< Base >' as specified by the user. +	    // A similar fix should also be done in upcastsCode in java.cxx, csharp.cxx and writeClassUpcast in d.cxx. +	    // Printf(stdout, "smartcomparison %s <=> %s\n", SwigType_namestr(bsmart), Getattr(bclass, "feature:smartptr")); + +	    Delete(rclsname); +	    Delete(rbname); +	    String *smartnamestr = SwigType_namestr(smart); +	    String *bsmartnamestr = SwigType_namestr(bsmart); +	    /* construct casting code */ +	    String *convcode = NewStringf("\n    *newmemory = SWIG_CAST_NEW_MEMORY;\n    return (void *) new %s(*(%s *)$from);\n", bsmartnamestr, smartnamestr); +	    Delete(bsmartnamestr); +	    Delete(smartnamestr); +	    /* setup inheritance relationship between smart pointer templates */ +	    SwigType_inherit(smart, bsmart, 0, convcode); +	    if (!GetFlag(bclass, "feature:smartptr")) +	      Swig_warning(WARN_LANG_SMARTPTR_MISSING, Getfile(first), Getline(first), "Base class '%s' of '%s' is not similarly marked as a smart pointer.\n", SwigType_namestr(Getattr(bclass, "name")), SwigType_namestr(Getattr(first, "name"))); +	    Delete(convcode); +	    Delete(bsmart); +	  } +	  Delete(smart); +	} else { +	  if (GetFlag(bclass, "feature:smartptr")) +	    Swig_warning(WARN_LANG_SMARTPTR_MISSING, Getfile(first), Getline(first), "Derived class '%s' of '%s' is not similarly marked as a smart pointer.\n", SwigType_namestr(Getattr(first, "name")), SwigType_namestr(Getattr(bclass, "name"))); +	} +      } +      if (!importmode) { +	String *btype = Copy(bname); +	SwigType_add_pointer(btype); +	SwigType_remember(btype); +	Delete(btype); +      } +      if (scopes) { +	SwigType_inherit_scope(scopes); +      } +      /* Set up inheritance in the symbol table */ +      Symtab *st = Getattr(cls, "symtab"); +      Symtab *bst = Getattr(bclass, "symtab"); +      if (st == bst) { +	Swig_warning(WARN_PARSE_REC_INHERITANCE, Getfile(cls), Getline(cls), "Recursive scope inheritance of '%s'.\n", SwigType_namestr(Getattr(cls, "name"))); +	continue; +      } +      Symtab *s = Swig_symbol_current(); +      Swig_symbol_setscope(st); +      Swig_symbol_inherit(bst); +      Swig_symbol_setscope(s); + +      /* Recursively hit base classes */ +      String *namestr = SwigType_namestr(Getattr(bclass, "name")); +      String *newcast = NewStringf("(%s *)%s", namestr, cast); +      Delete(namestr); +      cplus_inherit_types_impl(first, bclass, clsname, bases, baselist, ispublic, newcast); +      Delete(newcast); +    } +  } + +  void append_list(List *lb, List *la) { +    if (la && lb) { +      for (Iterator bi = First(la); bi.item; bi = Next(bi)) { +	Append(lb, bi.item); +      } +    } +  } + +  void cplus_inherit_types(Node *first, Node *cls, String *clsname, String *cast = 0) { +    cplus_inherit_types_impl(first, cls, clsname, "bases", "baselist", 1, cast); +    cplus_inherit_types_impl(first, cls, clsname, "protectedbases", "protectedbaselist", 0, cast); +    cplus_inherit_types_impl(first, cls, clsname, "privatebases", "privatebaselist", 0, cast); + +    if (!cls) +      cls = first; + +    List *allbases = NewList(); +    append_list(allbases, Getattr(cls, "bases")); +    append_list(allbases, Getattr(cls, "protectedbases")); +    append_list(allbases, Getattr(cls, "privatebases")); +    if (Len(allbases)) { +      Setattr(cls, "allbases", allbases); +    } +    Delete(allbases); +  } + +  /* ------------------------------------------------------------ +   * top() +   * ------------------------------------------------------------ */ + +  virtual int top(Node *n) { +    importmode = 0; +    module = Getattr(n, "module"); +    inclass = 0; +    normalize = 0; +    nsname = 0; +    nssymname = 0; +    classhash = Getattr(n, "classes"); +    emit_children(n); +    normalize_list(); +    SwigType_set_scope(0); +    return SWIG_OK; +  } + + +  /* ------------------------------------------------------------ +   * moduleDirective() +   * ------------------------------------------------------------ */ + +  virtual int moduleDirective(Node *n) { +    if (!module) { +      module = n; +    } +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * importDirective() +   * ------------------------------------------------------------ */ + +  virtual int importDirective(Node *n) { +    String *oldmodule = module; +    int oldimport = importmode; +    importmode = 1; +    module = 0; +    emit_children(n); +    importmode = oldimport; +    module = oldmodule; +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * includeDirective() +   * externDirective() +   * extendDirective() +   * ------------------------------------------------------------ */ + +  virtual int includeDirective(Node *n) { +    return emit_children(n); +  } +  virtual int externDeclaration(Node *n) { +    return emit_children(n); +  } +  virtual int extendDirective(Node *n) { +    return emit_children(n); +  } + +  /* ------------------------------------------------------------ +   * classDeclaration() +   * ------------------------------------------------------------ */ + +  virtual int classDeclaration(Node *n) { +    String *name = Getattr(n, "name"); +    String *tdname = Getattr(n, "tdname"); +    String *unnamed = Getattr(n, "unnamed"); +    String *storage = Getattr(n, "storage"); +    String *kind = Getattr(n, "kind"); +    save_value<Node*> oldinclass(inclass); +    List *olist = normalize; +    Symtab *symtab; +    String *nname = 0; +    String *fname = 0; +    String *scopename = 0; +    String *template_default_expanded = 0; + +    normalize = NewList(); + +    if (name) { +      if (SwigType_istemplate(name)) { +	// We need to fully resolve the name and expand default template parameters to make templates work correctly */ +	Node *cn; +	SwigType *resolved_name = SwigType_typedef_resolve_all(name); +	SwigType *deftype_name = Swig_symbol_template_deftype(resolved_name, 0); +	fname = Copy(resolved_name); +	if (!Equal(resolved_name, deftype_name)) +	  template_default_expanded = Copy(deftype_name); +	if (!Equal(fname, name) && (cn = Swig_symbol_clookup_local(fname, 0))) { +	  if ((n == cn) +	      || (Strcmp(nodeType(cn), "template") == 0) +	      || (Getattr(cn, "feature:onlychildren") != 0) +	      || (Getattr(n, "feature:onlychildren") != 0)) { +	    Swig_symbol_cadd(fname, n); +	    if (template_default_expanded) +	      Swig_symbol_cadd(template_default_expanded, n); +	    SwigType_typedef_class(fname); +	    scopename = Copy(fname); +	  } else { +	    Swig_warning(WARN_TYPE_REDEFINED, Getfile(n), Getline(n), "Template '%s' was already wrapped,\n", SwigType_namestr(name)); +	    Swig_warning(WARN_TYPE_REDEFINED, Getfile(cn), Getline(cn), "previous wrap of '%s'.\n", SwigType_namestr(Getattr(cn, "name"))); +	    scopename = 0; +	  } +	} else { +	  Swig_symbol_cadd(fname, n); +	  SwigType_typedef_class(fname); +	  scopename = Copy(fname); +	} +	Delete(deftype_name); +	Delete(resolved_name); +      } else { +	if ((CPlusPlus) || (unnamed)) { +	  SwigType_typedef_class(name); +	} else { +	  SwigType_typedef_class(NewStringf("%s %s", kind, name)); +	} +	scopename = Copy(name); +      } +    } else { +      scopename = 0; +    } + +    Setattr(n, "typepass:visit", "1"); + +    /* Need to set up a typedef if unnamed */ +    if (unnamed && tdname && (Cmp(storage, "typedef") == 0)) { +      SwigType_typedef(unnamed, tdname); +    } +    // name of the outer class should already be patched to contain its outer classes names, but not to contain namespaces +    // namespace name (if present) is added after processing child nodes +    if (Getattr(n, "nested:outer") && name) { +      String *outerName = Getattr(Getattr(n, "nested:outer"), "name"); +      name = NewStringf("%s::%s", outerName, name); +      Setattr(n, "name", name); +      if (tdname) { +	tdname = NewStringf("%s::%s", outerName, tdname); +	Setattr(n, "tdname", tdname); +      } +    } + +    if (nsname && name) { +      nname = NewStringf("%s::%s", nsname, name); +      String *tdname = Getattr(n, "tdname"); +      if (tdname) { +	tdname = NewStringf("%s::%s", nsname, tdname); +	Setattr(n, "tdname", tdname); +      } +    } +    if (nssymname) { +      if (GetFlag(n, "feature:nspace")) +	Setattr(n, "sym:nspace", nssymname); +    } +    SwigType_new_scope(scopename); +    SwigType_attach_symtab(Getattr(n, "symtab")); + +    /* Inherit type definitions into the class */ +    if (name && !(GetFlag(n, "nested") && !checkAttribute(n, "access", "public") &&  +      (GetFlag(n, "feature:flatnested") || Language::instance()->nestedClassesSupport() == Language::NCS_None))) { +      cplus_inherit_types(n, 0, nname ? nname : (fname ? fname : name)); +    } + +    inclass = n; +    symtab = Swig_symbol_setscope(Getattr(n, "symtab")); +    emit_children(n); +    Swig_symbol_setscope(symtab); + +    Hash *ts = SwigType_pop_scope(); +    Setattr(n, "typescope", ts); +    Delete(ts); +    Setattr(n, "module", module); + +    // When a fully qualified templated type with default parameters is used in the parsed code,  +    // the following additional symbols and scopes are needed for successful lookups +    if (template_default_expanded) { +      Swig_symbol_alias(template_default_expanded, Getattr(n, "symtab")); +      SwigType_scope_alias(template_default_expanded, Getattr(n, "typescope")); +    } + +    /* Normalize deferred types */ +    { +      normal_node *nn = new normal_node(); +      nn->normallist = normalize; +      nn->symtab = Getattr(n, "symtab"); +      nn->next = patch_list; +      nn->typescope = Getattr(n, "typescope"); +      patch_list = nn; +    } + +    normalize = olist; + +    /* If in a namespace, patch the class name */ +    if (nname) { +      Setattr(n, "name", nname); +      Delete(nname); +    } +    Delete(fname); +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * templateDeclaration() +   * ------------------------------------------------------------ */ + +  virtual int templateDeclaration(Node *n) { +    String *name = Getattr(n, "name"); +    String *ttype = Getattr(n, "templatetype"); +    if (Strcmp(ttype, "class") == 0) { +      String *rname = SwigType_typedef_resolve_all(name); +      SwigType_typedef_class(rname); +      Delete(rname); +    } else if (Strcmp(ttype, "classforward") == 0) { +      String *rname = SwigType_typedef_resolve_all(name); +      SwigType_typedef_class(rname); +      Delete(rname); +      /*      SwigType_typedef_class(name); */ +    } else if (Strcmp(ttype, "cdecl") == 0) { +      String *rname = SwigType_typedef_resolve_all(name); +      SwigType_typedef_class(rname); +      Delete(rname); +    } +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * lambdaDeclaration() +   * ------------------------------------------------------------ */ + +  virtual int lambdaDeclaration(Node *) { +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * classforwardDeclaration() +   * ------------------------------------------------------------ */ + +  virtual int classforwardDeclaration(Node *n) { + +    /* Can't do inside a C struct because it breaks C nested structure wrapping */ +    if ((!inclass) || (CPlusPlus)) { +      String *name = Getattr(n, "name"); +      SwigType_typedef_class(name); +    } +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * namespaceDeclaration() +   * ------------------------------------------------------------ */ + +  virtual int namespaceDeclaration(Node *n) { +    Symtab *symtab; +    String *name = Getattr(n, "name"); +    String *alias = Getattr(n, "alias"); +    List *olist = normalize; +    normalize = NewList(); +    if (alias) { +      Typetab *ts = Getattr(n, "typescope"); +      if (!ts) { +	/* Create an empty scope for the alias */ +	Node *ns = Getattr(n, "namespace"); +	SwigType_scope_alias(name, Getattr(ns, "typescope")); +	ts = Getattr(ns, "typescope"); +	Setattr(n, "typescope", ts); +      } +      /* Namespace alias */ +      return SWIG_OK; +    } else { +      if (name) { +	Node *nn = Swig_symbol_clookup(name, n); +	Hash *ts = 0; +	if (nn) +	  ts = Getattr(nn, "typescope"); +	if (!ts) { +	  SwigType_new_scope(name); +	  SwigType_attach_symtab(Getattr(n, "symtab")); +	} else { +	  SwigType_set_scope(ts); +	} +      } +      String *oldnsname = nsname; +      String *oldnssymname = nssymname; +      nsname = Swig_symbol_qualified(Getattr(n, "symtab")); +      nssymname = Swig_symbol_qualified_language_scopename(Getattr(n, "symtab")); +      symtab = Swig_symbol_setscope(Getattr(n, "symtab")); +      emit_children(n); +      Swig_symbol_setscope(symtab); + +      if (name) { +	Hash *ts = SwigType_pop_scope(); +	Setattr(n, "typescope", ts); +	Delete(ts); +      } + +      /* Normalize deferred types */ +      { +	normal_node *nn = new normal_node(); +	nn->normallist = normalize; +	nn->symtab = Getattr(n, "symtab"); +	nn->next = patch_list; +	nn->typescope = Getattr(n, "typescope"); +	patch_list = nn; +      } +      normalize = olist; + +      Delete(nssymname); +      nssymname = oldnssymname; +      Delete(nsname); +      nsname = oldnsname; +      return SWIG_OK; +    } +  } + +  /* ------------------------------------------------------------ +   * cDeclaration() +   * ------------------------------------------------------------ */ + +  virtual int cDeclaration(Node *n) { +    if (NoExcept) { +      Delattr(n, "throws"); +    } + +    /* Normalize types. */ +    SwigType *ty = Getattr(n, "type"); +    if (!ty) { +      return SWIG_OK; +    } +    normalize_type(ty); +    SwigType *decl = Getattr(n, "decl"); +    if (decl) { +      normalize_type(decl); +    } +    normalize_parms(Getattr(n, "parms")); +    normalize_parms(Getattr(n, "throws")); +    if (GetFlag(n, "conversion_operator")) { +      /* The call to the operator in the generated wrapper must be fully qualified in order to compile */ +      SwigType *name = Getattr(n, "name"); +      SwigType *qualifiedname = Swig_symbol_string_qualify(name, 0); +      Clear(name); +      Append(name, qualifiedname); +      Delete(qualifiedname); +    } + +    if (checkAttribute(n, "storage", "typedef")) { +      String *name = Getattr(n, "name"); +      ty = Getattr(n, "type"); +      decl = Getattr(n, "decl"); +      SwigType *t = Copy(ty); +      { +	/* If the typename is qualified, make sure the scopename is fully qualified when making a typedef */ +	if (Swig_scopename_check(t) && strncmp(Char(t), "::", 2)) { +	  String *base, *prefix, *qprefix; +	  base = Swig_scopename_last(t); +	  prefix = Swig_scopename_prefix(t); +	  qprefix = SwigType_typedef_qualified(prefix); +	  Delete(t); +	  t = NewStringf("%s::%s", qprefix, base); +	  Delete(base); +	  Delete(prefix); +	  Delete(qprefix); +	} +      } +      SwigType_push(t, decl); +      if (CPlusPlus) { +	Replaceall(t, "struct ", ""); +	Replaceall(t, "union ", ""); +	Replaceall(t, "class ", ""); +      } +      SwigType_typedef(t, name); +    } +    /* If namespaces are active.  We need to patch the name with a namespace prefix */ +    if (nsname && !inclass) { +      String *name = Getattr(n, "name"); +      if (name) { +	String *nname = NewStringf("%s::%s", nsname, name); +	Setattr(n, "name", nname); +	Delete(nname); +      } +    } +    clean_overloaded(n); +    return SWIG_OK; +  } + + +  /* ------------------------------------------------------------ +   * constructorDeclaration() +   * ------------------------------------------------------------ */ + +  virtual int constructorDeclaration(Node *n) { +    if (NoExcept) { +      Delattr(n, "throws"); +    } + +    normalize_parms(Getattr(n, "parms")); +    normalize_parms(Getattr(n, "throws")); + +    clean_overloaded(n); +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * destructorDeclaration() +   * ------------------------------------------------------------ */ + +  virtual int destructorDeclaration(Node *) { +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * constantDirective() +   * ------------------------------------------------------------ */ + +  virtual int constantDirective(Node *n) { +    SwigType *ty = Getattr(n, "type"); +    if (ty) { +      Setattr(n, "type", SwigType_typedef_qualified(ty)); +    } +    return SWIG_OK; +  } + + +  /* ------------------------------------------------------------ +   * enumDeclaration() +   * ------------------------------------------------------------ */ + +  virtual int enumDeclaration(Node *n) { +    String *name = Getattr(n, "name"); + +    if (name) { +      String *scope = 0; + +      // Add a typedef to the type table so that we can use 'enum Name' as well as just 'Name' +      if (nsname || inclass) { + +	// But first correct the name and tdname to contain the fully qualified scopename +	if (nsname && inclass) { +	  scope = NewStringf("%s::%s", nsname, Getattr(inclass, "name")); +	} else if (nsname) { +	  scope = NewStringf("%s", nsname); +	} else if (inclass) { +	  scope = NewStringf("%s", Getattr(inclass, "name")); +	} + +	String *nname = NewStringf("%s::%s", scope, name); +	Setattr(n, "name", nname); + +	String *tdname = Getattr(n, "tdname"); +	if (tdname) { +	  tdname = NewStringf("%s::%s", scope, tdname); +	  Setattr(n, "tdname", tdname); +	} + +	SwigType *t = NewStringf("enum %s", nname); +	SwigType_typedef(t, name); +      } else { +	SwigType *t = NewStringf("enum %s", name); +	SwigType_typedef(t, name); +      } +      Delete(scope); +    } + +    String *tdname = Getattr(n, "tdname"); +    String *unnamed = Getattr(n, "unnamed"); +    String *storage = Getattr(n, "storage"); + +    // Construct enumtype - for declaring an enum of this type with SwigType_ltype() etc +    String *enumtype = 0; +    if (unnamed && tdname && (Cmp(storage, "typedef") == 0)) { +      enumtype = Copy(Getattr(n, "tdname")); +    } else if (name) { +      enumtype = NewStringf("%s%s", CPlusPlus ? "" : "enum ", Getattr(n, "name")); +    } else { +      // anonymous enums +      enumtype = Copy(Getattr(n, "type")); +    } +    Setattr(n, "enumtype", enumtype); + +    if (nssymname) { +      if (GetFlag(n, "feature:nspace")) +	Setattr(n, "sym:nspace", nssymname); +    } + +    // This block of code is for dealing with %ignore on an enum item where the target language +    // attempts to use the C enum value in the target language itself and expects the previous enum value +    // to be one more than the previous value... the previous enum item might not exist if it is ignored! +    // - It sets the first non-ignored enum item with the "firstenumitem" attribute. +    // - It adds an enumvalue attribute if the previous enum item is ignored +    { +      Node *c; +      int count = 0; +      String *previous = 0; +      bool previous_ignored = false; +      bool firstenumitem = false; +      for (c = firstChild(n); c; c = nextSibling(c)) { +	assert(strcmp(Char(nodeType(c)), "enumitem") == 0); + +	bool reset; +	String *enumvalue = Getattr(c, "enumvalue"); +	if (GetFlag(c, "feature:ignore") || !Getattr(c, "sym:name")) { +	  reset = enumvalue ? true : false; +	  previous_ignored = true; +	} else { +	  if (!enumvalue && previous_ignored) { +	    if (previous) +	      Setattr(c, "enumvalue", NewStringf("(%s) + %d", previous, count+1)); +	    else +	      Setattr(c, "enumvalue", NewStringf("%d", count)); +	    SetFlag(c, "virtenumvalue"); // identify enumvalue as virtual, ie not from the parsed source +	  } +	  if (!firstenumitem) { +	    SetFlag(c, "firstenumitem"); +	    firstenumitem = true; +	  } +	  reset = true; +	  previous_ignored = false; +	} +	if (reset) { +	  previous = enumvalue ? enumvalue : Getattr(c, "name"); +	  count = 0; +	} else { +	  count++; +	} +      } +    } + +    emit_children(n); +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * enumvalueDeclaration() +   * ------------------------------------------------------------ */ + +  virtual int enumvalueDeclaration(Node *n) { +    String *name = Getattr(n, "name"); +    String *value = Getattr(n, "value"); +    String *scopedenum = Getattr(parentNode(n), "scopedenum"); +    if (!value) +      value = name; +    if (Strcmp(value, name) == 0) { +      String *new_value; +      if ((nsname || inclass || scopedenum) && cparse_cplusplus) { +	new_value = NewStringf("%s::%s", SwigType_namestr(Swig_symbol_qualified(n)), value); +      } else { +	new_value = NewString(value); +      } +      if ((nsname || inclass || scopedenum) && !cparse_cplusplus) { +	String *cppvalue = NewStringf("%s::%s", SwigType_namestr(Swig_symbol_qualified(n)), value); +	Setattr(n, "cppvalue", cppvalue); /* for target languages that always generate C++ code even when wrapping C code */ +      } +      Setattr(n, "value", new_value); +      Delete(new_value); +    } +    Node *next = nextSibling(n); + +    // Make up an enumvalue if one was not specified in the parsed code (not designed to be used on enum items and %ignore - enumvalue will be set instead) +    if (!GetFlag(n, "feature:ignore")) { +      if (Getattr(n, "_last") && !Getattr(n, "enumvalue")) {	// Only the first enum item has _last set (Note: first non-ignored enum item has firstenumitem set) +	Setattr(n, "enumvalueex", "0"); +      } +      if (next && !Getattr(next, "enumvalue")) { +	Setattr(next, "enumvalueex", NewStringf("%s + 1", Getattr(n, "sym:name"))); +      } +    } + +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * enumforwardDeclaration() +   * ------------------------------------------------------------ */ + +  virtual int enumforwardDeclaration(Node *n) { + +    // Use enumDeclaration() to do all the hard work. +    // Note that no children can be emitted in a forward declaration as there aren't any. +    int result = enumDeclaration(n); +    if (result == SWIG_OK) { +      // Detect when the real enum matching the forward enum declaration has not been parsed/declared +      SwigType *ty = SwigType_typedef_resolve_all(Getattr(n, "type")); +      Replaceall(ty, "enum ", ""); +      Node *nn = Swig_symbol_clookup(ty, 0); + +      String *nodetype = nn ? nodeType(nn) : 0; +      if (nodetype) { +	if (Equal(nodetype, "enumforward")) { +	  SetFlag(nn, "enumMissing"); +	} // if a real enum was declared this would be an "enum" node type +      } +      Delete(ty); +    } +    return result; +  } + +#ifdef DEBUG_OVERLOADED +  static void show_overloaded(Node *n) { +    Node *c = Getattr(n, "sym:overloaded"); +    Node *checkoverloaded = c; +    Printf(stdout, "-------------------- overloaded start %s sym:overloaded():%p -------------------------------\n", Getattr(n, "name"), c); +    while (c) { +      if (Getattr(c, "error")) { +        c = Getattr(c, "sym:nextSibling"); +        continue; +      } +      if (Getattr(c, "sym:overloaded") != checkoverloaded) { +        Printf(stdout, "sym:overloaded error c:%p checkoverloaded:%p\n", c, checkoverloaded); +        Swig_print_node(c); +        Exit(EXIT_FAILURE); +      } + +      String *decl = Strcmp(nodeType(c), "using") == 0 ? NewString("------") : Getattr(c, "decl"); +      Printf(stdout, "  show_overloaded %s::%s(%s)          [%s] nodeType:%s\n", parentNode(c) ? Getattr(parentNode(c), "name") : "NOPARENT", Getattr(c, "name"), decl, Getattr(c, "sym:overname"), nodeType(c)); +      if (!Getattr(c, "sym:overloaded")) { +        Printf(stdout, "sym:overloaded error.....%p\n", c); +        Swig_print_node(c); +        Exit(EXIT_FAILURE); +      } +      c = Getattr(c, "sym:nextSibling"); +    } +    Printf(stdout, "-------------------- overloaded end   %s -------------------------------\n", Getattr(n, "name")); +  } +#endif + +  /* ------------------------------------------------------------ +   * usingDeclaration() +   * ------------------------------------------------------------ */ + +  virtual int usingDeclaration(Node *n) { +    if (Getattr(n, "namespace")) { +      /* using namespace id */ + +      /* For a namespace import.   We set up inheritance in the type system */ +      Node *ns = Getattr(n, "node"); +      if (ns) { +	Typetab *ts = Getattr(ns, "typescope"); +	if (ts) { +	  SwigType_using_scope(ts); +	} +      } +      return SWIG_OK; +    } else { +      Node *ns; +      /* using id */ +      Symtab *stab = Getattr(n, "sym:symtab"); +      if (stab) { +	String *uname = Getattr(n, "uname"); +	ns = Swig_symbol_clookup(uname, stab); +	if (!ns && SwigType_istemplate(uname)) { +	  String *tmp = Swig_symbol_template_deftype(uname, 0); +	  if (!Equal(tmp, uname)) { +	    ns = Swig_symbol_clookup(tmp, stab); +	  } +	  Delete(tmp); +	} +      } else { +	ns = 0; +      } +      if (!ns) { +	if (is_public(n)) { +	  Swig_warning(WARN_PARSE_USING_UNDEF, Getfile(n), Getline(n), "Nothing known about '%s'.\n", SwigType_namestr(Getattr(n, "uname"))); +	} +      } else { +	/* Only a single symbol is being used.  There are only a few symbols that +	   we actually care about.  These are typedef, class declarations, and enum */ +	String *ntype = nodeType(ns); +	if (Strcmp(ntype, "cdecl") == 0) { +	  if (checkAttribute(ns, "storage", "typedef")) { +	    /* A typedef declaration */ +	    String *uname = Getattr(n, "uname"); +	    SwigType_typedef_using(uname); +	  } else { +	    /* A normal C declaration. */ +	    if ((inclass) && (!GetFlag(n, "feature:ignore")) && (Getattr(n, "sym:name"))) { +	      Node *c = ns; +	      Node *unodes = 0, *last_unodes = 0; +	      int ccount = 0; +	      String *symname = Getattr(n, "sym:name"); + +	      // The overloaded functions in scope may not yet have had their parameters normalized yet (in cDeclaration). +	      // Happens if the functions were declared after the using declaration. So use a normalized copy. +	      List *n_decl_list = NewList(); +	      Node *over = Getattr(n, "sym:overloaded"); +	      while (over) { +		String *odecl = Copy(Getattr(over, "decl")); +		if (odecl) { +		  normalize_type(odecl); +		  Append(n_decl_list, odecl); +		  Delete(odecl); +		} +		over = Getattr(over, "sym:nextSibling"); +	      } + +	      while (c) { +		if (Strcmp(nodeType(c), "cdecl") == 0) { +		  if (!(Swig_storage_isstatic(c) +			|| checkAttribute(c, "storage", "typedef") +			|| checkAttribute(c, "storage", "friend") +			|| (Getattr(c, "feature:extend") && !Getattr(c, "code")) +			|| GetFlag(c, "feature:ignore"))) { + +		    String *csymname = Getattr(c, "sym:name"); +		    if (!csymname || (Strcmp(csymname, symname) == 0)) { +		      String *decl = Getattr(c, "decl"); +		      int match = 0; + +		      for (Iterator it = First(n_decl_list); it.item; it = Next(it)) { +			String *odecl = it.item; +			if (Cmp(decl, odecl) == 0) { +			  match = 1; +			  break; +			} +		      } +		      if (match) { +			/* Don't generate a method if the method is overridden in this class, +			 * for example don't generate another m(bool) should there be a Base::m(bool) : +			 * struct Derived : Base { +			 *   void m(bool); +			 *   using Base::m; +			 * }; +			 */ +			c = Getattr(c, "csym:nextSibling"); +			continue; +		      } + +		      Node *nn = copyNode(c); +		      Setfile(nn, Getfile(n)); +		      Setline(nn, Getline(n)); +		      Delattr(nn, "access");	// access might be different from the method in the base class +		      Setattr(nn, "access", Getattr(n, "access")); +		      if (!Getattr(nn, "sym:name")) +			Setattr(nn, "sym:name", symname); +		      Symtab *st = Getattr(n, "sym:symtab"); +		      assert(st); +		      Setattr(nn, "sym:symtab", st); + +		      if (!GetFlag(nn, "feature:ignore")) { +			ParmList *parms = CopyParmList(Getattr(c, "parms")); +			int is_pointer = SwigType_ispointer_return(Getattr(nn, "decl")); +			int is_void = checkAttribute(nn, "type", "void") && !is_pointer; +			Setattr(nn, "parms", parms); +			Delete(parms); +			if (Getattr(n, "feature:extend")) { +			  String *ucode = is_void ? NewStringf("{ self->%s(", Getattr(n, "uname")) : NewStringf("{ return self->%s(", Getattr(n, "uname")); + +			  for (ParmList *p = parms; p;) { +			    Append(ucode, Getattr(p, "name")); +			    p = nextSibling(p); +			    if (p) +			      Append(ucode, ","); +			  } +			  Append(ucode, "); }"); +			  Setattr(nn, "code", ucode); +			  Delete(ucode); +			} +			ParmList *throw_parm_list = Getattr(c, "throws"); +			if (throw_parm_list) +			  Setattr(nn, "throws", CopyParmList(throw_parm_list)); +			ccount++; +			if (!last_unodes) { +			  last_unodes = nn; +			  unodes = nn; +			} else { +			  Setattr(nn, "previousSibling", last_unodes); +			  Setattr(last_unodes, "nextSibling", nn); +			  Setattr(nn, "sym:previousSibling", last_unodes); +			  Setattr(last_unodes, "sym:nextSibling", nn); +			  Setattr(nn, "sym:overloaded", unodes); +			  Setattr(unodes, "sym:overloaded", unodes); +			  last_unodes = nn; +			} +		      } else { +			Delete(nn); +		      } +		    } else { +		      Swig_warning(WARN_LANG_USING_NAME_DIFFERENT, Getfile(n), Getline(n), "Using declaration %s, with name '%s', is not actually using\n", SwigType_namestr(Getattr(n, "uname")), symname); +		      Swig_warning(WARN_LANG_USING_NAME_DIFFERENT, Getfile(c), Getline(c), "the method from %s, with name '%s', as the names are different.\n", Swig_name_decl(c), csymname); +		    } +		  } +		} +		c = Getattr(c, "csym:nextSibling"); +	      } +	      if (unodes) { +		set_firstChild(n, unodes); +		if (ccount > 1) { +		  if (!Getattr(n, "sym:overloaded")) { +		    Setattr(n, "sym:overloaded", n); +		    Setattr(n, "sym:overname", "_SWIG_0"); +		  } +		} +	      } + +	      /* Hack the parse tree symbol table for overloaded methods. Replace the "using" node with the +	       * list of overloaded methods we have just added in as child nodes to the "using" node. +	       * The node will still exist, it is just the symbol table linked list of overloaded methods +	       * which is hacked. */ +	      if (Getattr(n, "sym:overloaded")) { +		int cnt = 0; +		Node *ps = Getattr(n, "sym:previousSibling"); +		Node *ns = Getattr(n, "sym:nextSibling"); +		Node *fc = firstChild(n); +		Node *firstoverloaded = Getattr(n, "sym:overloaded"); +#ifdef DEBUG_OVERLOADED +		show_overloaded(firstoverloaded); +#endif + +		if (firstoverloaded == n) { +		  // This 'using' node we are cutting out was the first node in the overloaded list.  +		  // Change the first node in the list +		  Delattr(firstoverloaded, "sym:overloaded"); +		  firstoverloaded = fc ? fc : ns; + +		  // Correct all the sibling overloaded methods (before adding in new methods) +		  Node *nnn = ns; +		  while (nnn) { +		    Setattr(nnn, "sym:overloaded", firstoverloaded); +		    nnn = Getattr(nnn, "sym:nextSibling"); +		  } +		} + +		if (!fc) { +		  // Remove from overloaded list ('using' node does not actually end up adding in any methods) +		  if (ps) { +		    Setattr(ps, "sym:nextSibling", ns); +		  } +		  if (ns) { +		    Setattr(ns, "sym:previousSibling", ps); +		  } +		} else { +		  // The 'using' node results in methods being added in - slot in these methods here +		  Node *pp = fc; +		  while (pp) { +		    Node *ppn = Getattr(pp, "sym:nextSibling"); +		    Setattr(pp, "sym:overloaded", firstoverloaded); +		    Setattr(pp, "sym:overname", NewStringf("%s_%d", Getattr(n, "sym:overname"), cnt++)); +		    if (ppn) +		      pp = ppn; +		    else +		      break; +		  } +		  if (ps) { +		    Setattr(ps, "sym:nextSibling", fc); +		    Setattr(fc, "sym:previousSibling", ps); +		  } +		  if (ns) { +		    Setattr(ns, "sym:previousSibling", pp); +		    Setattr(pp, "sym:nextSibling", ns); +		  } +		} +		Delattr(n, "sym:previousSibling"); +		Delattr(n, "sym:nextSibling"); +		Delattr(n, "sym:overloaded"); +		Delattr(n, "sym:overname"); +		clean_overloaded(firstoverloaded); +#ifdef DEBUG_OVERLOADED +		show_overloaded(firstoverloaded); +#endif +	      } +	      Delete(n_decl_list); +	    } +	  } +	} else if ((Strcmp(ntype, "class") == 0) || ((Strcmp(ntype, "classforward") == 0))) { +	  /* We install the using class name as kind of a typedef back to the original class */ +	  String *uname = Getattr(n, "uname"); +	  /* Import into current type scope */ +	  SwigType_typedef_using(uname); +	} else if (Strcmp(ntype, "enum") == 0) { +	  SwigType_typedef_using(Getattr(n, "uname")); +	} else if (Strcmp(ntype, "template") == 0) { +	  SwigType_typedef_using(Getattr(n, "uname")); +	} +      } +    } +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * typemapDirective() +   * ------------------------------------------------------------ */ + +  virtual int typemapDirective(Node *n) { +    if (inclass || nsname) { +      Node *items = firstChild(n); +      while (items) { +	Parm *pattern = Getattr(items, "pattern"); +	Parm *parms = Getattr(items, "parms"); +	normalize_later(pattern); +	normalize_later(parms); +	items = nextSibling(items); +      } +    } +    return SWIG_OK; +  } + + +  /* ------------------------------------------------------------ +   * typemapcopyDirective() +   * ------------------------------------------------------------ */ + +  virtual int typemapcopyDirective(Node *n) { +    if (inclass || nsname) { +      Node *items = firstChild(n); +      ParmList *pattern = Getattr(n, "pattern"); +      normalize_later(pattern); +      while (items) { +	ParmList *npattern = Getattr(items, "pattern"); +	normalize_later(npattern); +	items = nextSibling(items); +      } +    } +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * applyDirective() +   * ------------------------------------------------------------ */ + +  virtual int applyDirective(Node *n) { +    if (inclass || nsname) { +      ParmList *pattern = Getattr(n, "pattern"); +      normalize_later(pattern); +      Node *items = firstChild(n); +      while (items) { +	Parm *apattern = Getattr(items, "pattern"); +	normalize_later(apattern); +	items = nextSibling(items); +      } +    } +    return SWIG_OK; +  } + +  /* ------------------------------------------------------------ +   * clearDirective() +   * ------------------------------------------------------------ */ + +  virtual int clearDirective(Node *n) { +    if (inclass || nsname) { +      Node *p; +      for (p = firstChild(n); p; p = nextSibling(p)) { +	ParmList *pattern = Getattr(p, "pattern"); +	normalize_later(pattern); +      } +    } +    return SWIG_OK; +  } + +public: +  static void pass(Node *n) { +    TypePass t; +    t.top(n); +  } +}; + +void Swig_process_types(Node *n) { +  if (!n) +    return; +  TypePass::pass(n); +} + diff --git a/contrib/tools/swig/Source/Modules/utils.cxx b/contrib/tools/swig/Source/Modules/utils.cxx new file mode 100644 index 00000000000..de6f87d8c3a --- /dev/null +++ b/contrib/tools/swig/Source/Modules/utils.cxx @@ -0,0 +1,218 @@ +/* -----------------------------------------------------------------------------  + * This file is part of SWIG, which is licensed as a whole under version 3  + * (or any later version) of the GNU General Public License. Some additional + * terms also apply to certain portions of SWIG. The full details of the SWIG + * license and copyrights can be found in the LICENSE and COPYRIGHT files + * included with the SWIG source code as distributed by the SWIG developers + * and at https://www.swig.org/legal.html. + * + * utils.cxx + * + * Various utility functions. + * ----------------------------------------------------------------------------- */ + +#include "swigmod.h" + +int is_public(Node *n) { +  String *access = Getattr(n, "access"); +  return !access || !Cmp(access, "public"); +} + +int is_private(Node *n) { +  String *access = Getattr(n, "access"); +  return access && !Cmp(access, "private"); +} + +int is_protected(Node *n) { +  String *access = Getattr(n, "access"); +  return access && !Cmp(access, "protected"); +} + +static int is_member_director_helper(Node *parentnode, Node *member) { +  int parent_nodirector = GetFlag(parentnode, "feature:nodirector"); +  if (parent_nodirector) +    return 0; +  int parent_director = Swig_director_mode() && GetFlag(parentnode, "feature:director"); +  int cdecl_director = parent_director || GetFlag(member, "feature:director"); +  int cdecl_nodirector = GetFlag(member, "feature:nodirector"); +  return cdecl_director && !cdecl_nodirector && !GetFlag(member, "feature:extend"); +} + +int is_member_director(Node *parentnode, Node *member) { +  if (parentnode && checkAttribute(member, "storage", "virtual")) { +    return is_member_director_helper(parentnode, member); +  } else { +    return 0; +  } +} + +int is_member_director(Node *member) { +  return is_member_director(Getattr(member, "parentNode"), member); +} + +// Identifies the additional protected members that are generated when the allprotected option is used. +// This does not include protected virtual methods as they are turned on with the dirprot option. +int is_non_virtual_protected_access(Node *n) { +  int result = 0; +  if (Swig_director_mode() && Swig_director_protected_mode() && Swig_all_protected_mode() && is_protected(n) && !checkAttribute(n, "storage", "virtual")) { +    Node *parentNode = Getattr(n, "parentNode"); +    // When vtable is empty, the director class does not get emitted, so a check for an empty vtable should be done. +    // However, vtable is set in Language and so is not yet set when methods in Typepass call clean_overloaded() +    // which calls is_non_virtual_protected_access. So commented out below. +    // Moving the director vtable creation into Typepass should solve this problem. +    if (is_member_director_helper(parentNode, n) /* && Getattr(parentNode, "vtable")*/) +      result = 1; +  } +  return result; +} + +/* Clean overloaded list.  Removes templates, ignored, and errors */ + +void clean_overloaded(Node *n) { +  Node *nn = Getattr(n, "sym:overloaded"); +  Node *first = 0; +  while (nn) { +    String *ntype = nodeType(nn); +    if ((GetFlag(nn, "feature:ignore")) || +	(Getattr(nn, "error")) || +	(Strcmp(ntype, "template") == 0) || +	((Strcmp(ntype, "cdecl") == 0) && is_protected(nn) && !is_member_director(nn) && !is_non_virtual_protected_access(n))) { +      /* Remove from overloaded list */ +      Node *ps = Getattr(nn, "sym:previousSibling"); +      Node *ns = Getattr(nn, "sym:nextSibling"); +      if (ps) { +	Setattr(ps, "sym:nextSibling", ns); +      } +      if (ns) { +	Setattr(ns, "sym:previousSibling", ps); +      } +      Delattr(nn, "sym:previousSibling"); +      Delattr(nn, "sym:nextSibling"); +      Delattr(nn, "sym:overloaded"); +      nn = ns; +      continue; +    } else { +      if (!first) +	first = nn; +      Setattr(nn, "sym:overloaded", first); +    } +    nn = Getattr(nn, "sym:nextSibling"); +  } +  if (!first || (first && !Getattr(first, "sym:nextSibling"))) { +    if (Getattr(n, "sym:overloaded")) +      Delattr(n, "sym:overloaded"); +  } +} + +/* ----------------------------------------------------------------------------- + * Swig_set_max_hash_expand() + * + * Controls how many Hash objects are displayed when displaying nested Hash objects. + * Makes DohSetMaxHashExpand an externally callable function (for debugger). + * ----------------------------------------------------------------------------- */ + +void Swig_set_max_hash_expand(int count) { +  SetMaxHashExpand(count); +} + +extern "C" { + +/* ----------------------------------------------------------------------------- + * Swig_get_max_hash_expand() + * + * Returns how many Hash objects are displayed when displaying nested Hash objects. + * Makes DohGetMaxHashExpand an externally callable function (for debugger). + * ----------------------------------------------------------------------------- */ + +int Swig_get_max_hash_expand() { +  return GetMaxHashExpand(); +} + +/* ----------------------------------------------------------------------------- + * Swig_to_doh_string() + * + * DOH version of Swig_to_string() + * ----------------------------------------------------------------------------- */ + +static String *Swig_to_doh_string(DOH *object, int count) { +  int old_count = Swig_get_max_hash_expand(); +  if (count >= 0) +    Swig_set_max_hash_expand(count); + +  String *debug_string = object ? NewStringf("%s", object) : NewString("NULL"); + +  Swig_set_max_hash_expand(old_count); +  return debug_string; +} + +/* ----------------------------------------------------------------------------- + * Swig_to_doh_string_with_location() + * + * DOH version of Swig_to_string_with_location() + * ----------------------------------------------------------------------------- */ + +static String *Swig_to_doh_string_with_location(DOH *object, int count) { +  int old_count = Swig_get_max_hash_expand(); +  if (count >= 0) +    Swig_set_max_hash_expand(count); + +  String *debug_string = Swig_stringify_with_location(object); + +  Swig_set_max_hash_expand(old_count); +  return debug_string; +} + +/* ----------------------------------------------------------------------------- + * Swig_to_string() + * + * Swig debug - return C string representation of any DOH type. + * Nested Hash types expand count is value of Swig_get_max_hash_expand when count<0 + * Note: leaks memory. + * ----------------------------------------------------------------------------- */ + +const char *Swig_to_string(DOH *object, int count) { +  return Char(Swig_to_doh_string(object, count)); +} + +/* ----------------------------------------------------------------------------- + * Swig_to_string_with_location() + * + * Swig debug - return C string representation of any DOH type, within [] brackets + * for Hash and List types, prefixed by line and file information. + * Nested Hash types expand count is value of Swig_get_max_hash_expand when count<0 + * Note: leaks memory. + * ----------------------------------------------------------------------------- */ + +const char *Swig_to_string_with_location(DOH *object, int count) { +  return Char(Swig_to_doh_string_with_location(object, count)); +} + +/* ----------------------------------------------------------------------------- + * Swig_print() + * + * Swig debug - display string representation of any DOH type. + * Nested Hash types expand count is value of Swig_get_max_hash_expand when count<0 + * ----------------------------------------------------------------------------- */ + +void Swig_print(DOH *object, int count) { +  String *output = Swig_to_doh_string(object, count); +  Printf(stdout, "%s\n", output); +  Delete(output); +} + +/* ----------------------------------------------------------------------------- + * Swig_to_string_with_location() + * + * Swig debug - display string representation of any DOH type, within [] brackets + * for Hash and List types, prefixed by line and file information. + * Nested Hash types expand count is value of Swig_get_max_hash_expand when count<0 + * ----------------------------------------------------------------------------- */ + +void Swig_print_with_location(DOH *object, int count) { +  String *output = Swig_to_doh_string_with_location(object, count); +  Printf(stdout, "%s\n", output); +  Delete(output); +} + +} // extern "C" + diff --git a/contrib/tools/swig/Source/Modules/xml.cxx b/contrib/tools/swig/Source/Modules/xml.cxx new file mode 100644 index 00000000000..ed4213cc5c3 --- /dev/null +++ b/contrib/tools/swig/Source/Modules/xml.cxx @@ -0,0 +1,326 @@ +/* ----------------------------------------------------------------------------- + * This file is part of SWIG, which is licensed as a whole under version 3  + * (or any later version) of the GNU General Public License. Some additional + * terms also apply to certain portions of SWIG. The full details of the SWIG + * license and copyrights can be found in the LICENSE and COPYRIGHT files + * included with the SWIG source code as distributed by the SWIG developers + * and at https://www.swig.org/legal.html. + * + * xml.cxx + * + * An Xml parse tree generator. + * ----------------------------------------------------------------------------- */ + +#include "swigmod.h" + +static const char *usage = "\ +XML Options (available with -xml)\n\ +     -xmllang <lang> - Typedef language\n\ +     -xmllite        - More lightweight version of XML\n\ +     ------\n\ +     deprecated (use -o): -xml <output.xml> - Use <output.xml> as output file (extension .xml mandatory)\n"; + +static File *out = 0; +static int xmllite = 0; + + +class XML:public Language { +public: + +  int indent_level; +  long id; + +  XML() :indent_level(0) , id(0) { +  } +   +  virtual ~ XML() { +  } + +  virtual void main(int argc, char *argv[]) { +    SWIG_typemap_lang("xml"); +    for (int iX = 0; iX < argc; iX++) { +      if (strcmp(argv[iX], "-xml") == 0) { +	char *extension = 0; +	if (iX + 1 >= argc) +	  continue; +	extension = argv[iX + 1] + strlen(argv[iX + 1]) - 4; +	if (strcmp(extension, ".xml")) +	  continue; +	iX++; +	Swig_mark_arg(iX); +	String *outfile = NewString(argv[iX]); +	out = NewFile(outfile, "w", SWIG_output_files()); +	if (!out) { +	  FileErrorDisplay(outfile); +	  Exit(EXIT_FAILURE); +	} +	continue; +      } +      if (strcmp(argv[iX], "-xmllang") == 0) { +	Swig_mark_arg(iX); +	iX++; +	SWIG_typemap_lang(argv[iX]); +	Swig_mark_arg(iX); +	continue; +      } +      if (strcmp(argv[iX], "-help") == 0) { +	fputs(usage, stdout); +      } +      if (strcmp(argv[iX], "-xmllite") == 0) { +	Swig_mark_arg(iX); +	xmllite = 1; +      } +    } + +    // Add a symbol to the parser for conditional compilation +    Preprocessor_define("SWIGXML 1", 0); +  } + +  /* Top of the parse tree */ + +  virtual int top(Node *n) { +    if (out == 0) { +      String *outfile = Getattr(n, "outfile"); +      String *ext = Swig_file_extension(outfile); +      // If there's an extension, ext will include the ".". +      Delslice(outfile, Len(outfile) - Len(ext), DOH_END); +      Delete(ext); +      Append(outfile, ".xml"); +      out = NewFile(outfile, "w", SWIG_output_files()); +      if (!out) { +	FileErrorDisplay(outfile); +	Exit(EXIT_FAILURE); +      } +    } +    Printf(out, "<?xml version=\"1.0\" ?> \n"); +    Xml_print_tree(n); +    return SWIG_OK; +  } + +  void print_indent(int l) { +    int i; +    for (i = 0; i < indent_level; i++) { +      Printf(out, " "); +    } +    if (l) { +      Printf(out, " "); +    } +  } + +  void Xml_print_tree(DOH *obj) { +    while (obj) { +      Xml_print_node(obj); +      obj = nextSibling(obj); +    } +  } + +  void Xml_print_attributes(Node *obj) { +    String *k; +    indent_level += 4; +    print_indent(0); +    Printf(out, "<attributelist id=\"%ld\" addr=\"%p\">\n", ++id, obj); +    indent_level += 4; +    Iterator ki; +    ki = First(obj); +    while (ki.key) { +      k = ki.key; +      if ((Cmp(k, "nodeType") == 0) +	  || (Cmp(k, "firstChild") == 0) +	  || (Cmp(k, "lastChild") == 0) +	  || (Cmp(k, "parentNode") == 0) +	  || (Cmp(k, "nextSibling") == 0) +	  || (Cmp(k, "previousSibling") == 0) +	  || (*(Char(k)) == '$')) { +	/* Do nothing */ +      } else if (Cmp(k, "module") == 0) { +	Xml_print_module(Getattr(obj, k)); +      } else if (Cmp(k, "baselist") == 0) { +	Xml_print_baselist(Getattr(obj, k)); +      } else if (!xmllite && Cmp(k, "typescope") == 0) { +	Xml_print_typescope(Getattr(obj, k)); +      } else if (!xmllite && Cmp(k, "typetab") == 0) { +	Xml_print_typetab(Getattr(obj, k)); +      } else if (Cmp(k, "kwargs") == 0) { +	Xml_print_kwargs(Getattr(obj, k)); +      } else if (Cmp(k, "parms") == 0 || Cmp(k, "pattern") == 0) { +	Xml_print_parmlist(Getattr(obj, k)); +      } else if (Cmp(k, "catchlist") == 0 || Cmp(k, "templateparms") == 0) { +	Xml_print_parmlist(Getattr(obj, k), Char(k)); +      } else { +	DOH *o; +	print_indent(0); +	if (DohIsString(Getattr(obj, k))) { +	  String *ck = NewString(k); +	  o = Str(Getattr(obj, k)); +	  Replaceall(ck, ":", "_"); +	  Replaceall(ck, "<", "<"); +	  /* Do first to avoid aliasing errors. */ +	  Replaceall(o, "&", "&"); +	  Replaceall(o, "<", "<"); +	  Replaceall(o, "\"", """); +	  Replaceall(o, "\\", "\\\\"); +	  Replaceall(o, "\n", "
"); +	  Printf(out, "<attribute name=\"%s\" value=\"%s\" id=\"%ld\" addr=\"%p\" />\n", ck, o, ++id, o); +	  Delete(o); +	  Delete(ck); +	} else { +	  o = Getattr(obj, k); +	  String *ck = NewString(k); +	  Replaceall(ck, ":", "_"); +	  Printf(out, "<attribute name=\"%s\" value=\"%p\" id=\"%ld\" addr=\"%p\" />\n", ck, o, ++id, o); +	  Delete(ck); +	} +      } +      ki = Next(ki); +    } +    indent_level -= 4; +    print_indent(0); +    Printf(out, "</attributelist>\n"); +    indent_level -= 4; +  } + +  void Xml_print_node(Node *obj) { +    Node *cobj; + +    print_indent(0); +    Printf(out, "<%s id=\"%ld\" addr=\"%p\">\n", nodeType(obj), ++id, obj); +    Xml_print_attributes(obj); +    cobj = firstChild(obj); +    if (cobj) { +      indent_level += 4; +      Printf(out, "\n"); +      Xml_print_tree(cobj); +      indent_level -= 4; +    } else { +      print_indent(1); +      Printf(out, "\n"); +    } +    print_indent(0); +    Printf(out, "</%s>\n", nodeType(obj)); +  } + + +  void Xml_print_parmlist(ParmList *p, const char* markup = "parmlist") { + +    print_indent(0); +    Printf(out, "<%s id=\"%ld\" addr=\"%p\">\n", markup, ++id, p); +    indent_level += 4; +    while (p) { +      print_indent(0); +      Printf(out, "<parm id=\"%ld\">\n", ++id); +      Xml_print_attributes(p); +      print_indent(0); +      Printf(out, "</parm>\n"); +      p = nextSibling(p); +    } +    indent_level -= 4; +    print_indent(0); +    Printf(out, "</%s>\n", markup); +  } + +  void Xml_print_baselist(List *p) { + +    print_indent(0); +    Printf(out, "<baselist id=\"%ld\" addr=\"%p\">\n", ++id, p); +    indent_level += 4; +    Iterator s; +    for (s = First(p); s.item; s = Next(s)) { +      print_indent(0); +      String *item_name = Xml_escape_string(s.item); +      Printf(out, "<base name=\"%s\" id=\"%ld\" addr=\"%p\" />\n", item_name, ++id, s.item); +      Delete(item_name); +    } +    indent_level -= 4; +    print_indent(0); +    Printf(out, "</baselist>\n"); +  } + +  String *Xml_escape_string(String *str) { +    String *escaped_str = 0; +    if (str) { +      escaped_str = NewString(str); +      Replaceall(escaped_str, "&", "&"); +      Replaceall(escaped_str, "<", "<"); +      Replaceall(escaped_str, "\"", """); +      Replaceall(escaped_str, "\\", "\\\\"); +      Replaceall(escaped_str, "\n", "
"); +    } +    return escaped_str; +  } + +  void Xml_print_module(Node *p) { + +    print_indent(0); +    Printf(out, "<attribute name=\"module\" value=\"%s\" id=\"%ld\" addr=\"%p\" />\n", Getattr(p, "name"), ++id, p); +  } + +  void Xml_print_kwargs(Hash *p) { +    Xml_print_hash(p, "kwargs"); +  } + +  void Xml_print_typescope(Hash *p) { + +    Xml_print_hash(p, "typescope"); +  } + +  void Xml_print_typetab(Hash *p) { + +    Xml_print_hash(p, "typetab"); +  } + + +  void Xml_print_hash(Hash *p, const char *markup) { + +    print_indent(0); +    Printf(out, "<%s id=\"%ld\" addr=\"%p\">\n", markup, ++id, p); +    Xml_print_attributes(p); +    indent_level += 4; +    Iterator n = First(p); +    while (n.key) { +      print_indent(0); +      Printf(out, "<%ssitem id=\"%ld\" addr=\"%p\">\n", markup, ++id, n.item); +      Xml_print_attributes(n.item); +      print_indent(0); +      Printf(out, "</%ssitem>\n", markup); +      n = Next(n); +    } +    indent_level -= 4; +    print_indent(0); +    Printf(out, "</%s>\n", markup); +  } + +}; + +/* ----------------------------------------------------------------------------- + * Swig_print_xml + * + * Dump an XML version of the parse tree.  This is different from using the -xml + * language module normally as it allows the real language module to process the + * tree first, possibly stuffing in new attributes, so the XML that is output ends + * up being a post-processing version of the tree. + * ----------------------------------------------------------------------------- */ + +void Swig_print_xml(DOH *obj, String *filename) { +  XML xml; +  xmllite = 1; + +  if (!filename) { +    out = stdout; +  } else { +    out = NewFile(filename, "w", SWIG_output_files()); +    if (!out) { +      FileErrorDisplay(filename); +      Exit(EXIT_FAILURE); +    } +  } + +  Printf(out, "<?xml version=\"1.0\" ?> \n"); +  xml.Xml_print_tree(obj); +} + +static Language *new_swig_xml() { +  return new XML(); +} +extern "C" Language *swig_xml(void) { +  return new_swig_xml(); +}  | 
