/* -----------------------------------------------------------------------------
 * This file is part of SWIG, which is licensed as a whole under version 3 
 * (or any later version) of the GNU General Public License. Some additional
 * terms also apply to certain portions of SWIG. The full details of the SWIG
 * license and copyrights can be found in the LICENSE and COPYRIGHT files
 * included with the SWIG source code as distributed by the SWIG developers
 * and at http://www.swig.org/legal.html.
 *
 * python.cxx
 *
 * Python language module for SWIG.
 * ----------------------------------------------------------------------------- */

char cvsroot_python_cxx[] = "$Id: python.cxx 12229 2010-09-27 01:16:29Z olly $";

#include "swigmod.h"
#include "cparse.h"

static int treduce = SWIG_cparse_template_reduce(0);

#include <ctype.h>

#define PYSHADOW_MEMBER  0x2

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 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_imports = 0;
static String *f_shadow_stubs = 0;

static String *methods;
static String *class_name;
static String *shadow_indent = 0;
static int in_class = 0;
static int classic = 0;
static int modern = 0;
static int new_repr = 1;
static int no_header_file = 0;

static int py3 = 0;

/* C++ Support + Shadow Classes */

static int have_constructor;
static int have_repr;
static String *real_classname;

/* Thread Support */
static int threads = 0;
static int nothreads = 0;
static int classptr = 0;
/* Other options */
static int shadowimport = 1;
static int buildnone = 0;
static int nobuildnone = 0;
static int safecstrings = 0;
static int dirvtable = 0;
static int proxydel = 1;
static int fastunpack = 0;
static int fastproxy = 0;
static int fastquery = 0;
static int fastinit = 0;
static int olddefs = 0;
static int modernargs = 0;
static int aliasobj0 = 0;
static int castmode = 0;
static int extranative = 0;
static int outputtuple = 0;
static int nortti = 0;

/* flags for the make_autodoc function */
enum autodoc_t {
  AUTODOC_CLASS,
  AUTODOC_CTOR,
  AUTODOC_DTOR,
  AUTODOC_STATICFUNC,
  AUTODOC_FUNC,
  AUTODOC_METHOD
};


static const char *usage1 = (char *) "\
Python Options (available with -python)\n\
     -aliasobj0      - Alias obj0 when using fastunpack, needed for some old typemaps \n\
     -buildnone      - Use Py_BuildValue(" ") to obtain Py_None (default in Windows)\n\
     -castmode       - Enable the casting mode, which allows implicit cast between types in python\n\
     -classic        - Use classic classes only\n\
     -classptr       - Generate shadow 'ClassPtr' as in older swig versions\n\
     -cppcast        - Enable C++ casting operators (default) \n\
     -dirvtable      - Generate a pseudo virtual table for directors for faster dispatch \n\
     -extranative    - Return extra native C++ wraps for std containers when possible \n\
     -fastinit       - Use fast init mechanism for classes (default)\n\
     -fastunpack     - Use fast unpack mechanism to parse the argument functions \n\
     -fastproxy      - Use fast proxy mechanism for member methods \n\
     -fastquery      - Use fast query mechanism for types \n\
     -globals <name> - Set <name> used to access C global variable [default: 'cvar']\n\
     -interface <lib>- Set the lib name to <lib>\n\
     -keyword        - Use keyword arguments\n\
     -modern         - Use modern python features only, without compatibility code\n\
     -modernargs     - Use \"modern\" args mechanism to pack/unpack the function arguments\n";
static const char *usage2 = (char *) "\
     -newrepr        - Use more informative version of __repr__ in proxy classes (default) \n\
     -newvwm         - New value wrapper mode, use only when everything else fails \n\
     -noaliasobj0    - Don't generate an obj0 alias when using fastunpack (default) \n\
     -nobuildnone    - Access Py_None directly (default in non-Windows systems)\n\
     -nocastmode     - Disable the casting mode (default)\n\
     -nocppcast      - Disable C++ casting operators, useful for generating bugs\n\
     -nodirvtable    - Don't use the virtual table feature, resolve the python method each time (default)\n\
     -noexcept       - No automatic exception handling\n\
     -noextranative  - Don't use extra native C++ wraps for std containers when possible (default) \n\
     -nofastinit     - Use traditional init mechanism for classes \n\
     -nofastunpack   - Use traditional UnpackTuple method to parse the argument functions (default) \n\
     -nofastproxy    - Use traditional proxy mechanism for member methods (default) \n\
     -nofastquery    - Use traditional query mechanism for types (default) \n\
     -noh            - Don't generate the output header file\n\
     -nomodern       - Don't use modern python features which are not back compatible \n\
     -nomodernargs   - Use classic ParseTuple/CallFunction methods to pack/unpack the function arguments (default) \n";
static const char *usage3 = (char *) "\
     -noolddefs      - Don't emit the old method definitions even when using fastproxy (default) \n\
     -nooutputtuple  - Use a PyList for appending output values (default) \n\
     -noproxy        - Don't generate proxy classes \n\
     -noproxydel     - Don't generate the redundant __del__ method \n\
     -noproxyimport  - Don't insert proxy import statements derived from the %import directive \n\
     -nortti         - Disable the use of the native C++ RTTI with directors\n\
     -nosafecstrings - Avoid extra strings copies when possible (default)\n\
     -nothreads      - Disable thread support for the entire interface\n\
     -olddefs        - Keep the old method definitions even when using fastproxy\n\
     -oldrepr        - Use shorter and old version of __repr__ in proxy classes\n\
     -outputtuple    - Use a PyTuple for outputs instead of a PyList (use carefully with legacy interfaces) \n\
     -proxydel       - Generate a __del__ method even though it is now redundant (default) \n\
     -safecstrings   - Use safer (but slower) C string mapping, generating copies from Python -> C/C++\n\
     -threads        - Add thread support for all the interface\n\
     -O              - Enable the following optimization options: \n\
                         -modern -fastdispatch -nosafecstrings -fvirtual -noproxydel \n\
                         -fastproxy -fastinit -fastunpack -fastquery -modernargs -nobuildnone \n\
     -py3            - Generate code with Python 3 specific features:\n\
                         Function annotation \n\
\n";

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;
  }

  /* ------------------------------------------------------------
   * 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[]) {
    int cppcast = 1;

    SWIG_library_directory("python");

    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();
	  }
	  /* end added */
	} 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], "-new_repr") == 0) || (strcmp(argv[i], "-newrepr") == 0)) {
	  new_repr = 1;
	  Swig_mark_arg(i);
	} else if ((strcmp(argv[i], "-old_repr") == 0) || (strcmp(argv[i], "-oldrepr") == 0)) {
	  new_repr = 0;
	  Swig_mark_arg(i);
	} else if (strcmp(argv[i], "-classptr") == 0) {
	  classptr = 1;
	  Swig_mark_arg(i);
	} else if ((strcmp(argv[i], "-noproxy") == 0)) {
	  shadow = 0;
	  Swig_mark_arg(i);
	} else if ((strcmp(argv[i], "-noproxyimport") == 0)) {
	  shadowimport = 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], "-classic") == 0) {
	  classic = 1;
	  modernargs = 0;
	  modern = 0;
	  Swig_mark_arg(i);
	} else if (strcmp(argv[i], "-cppcast") == 0) {
	  cppcast = 1;
	  Swig_mark_arg(i);
	} else if (strcmp(argv[i], "-nocppcast") == 0) {
	  cppcast = 0;
	  Swig_mark_arg(i);
	} else if (strcmp(argv[i], "-outputtuple") == 0) {
	  outputtuple = 1;
	  Swig_mark_arg(i);
	} else if (strcmp(argv[i], "-nooutputtuple") == 0) {
	  outputtuple = 0;
	  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 suppor mode */
	  nothreads = 1;
	  Swig_mark_arg(i);
	} else if (strcmp(argv[i], "-safecstrings") == 0) {
	  safecstrings = 1;
	  Swig_mark_arg(i);
	} else if (strcmp(argv[i], "-nosafecstrings") == 0) {
	  safecstrings = 0;
	  Swig_mark_arg(i);
	} else if (strcmp(argv[i], "-buildnone") == 0) {
	  buildnone = 1;
	  nobuildnone = 0;
	  Swig_mark_arg(i);
	} else if (strcmp(argv[i], "-nobuildnone") == 0) {
	  buildnone = 0;
	  nobuildnone = 1;
	  Swig_mark_arg(i);
	} else if (strcmp(argv[i], "-dirvtable") == 0) {
	  dirvtable = 1;
	  Swig_mark_arg(i);
	} else if (strcmp(argv[i], "-nodirvtable") == 0) {
	  dirvtable = 0;
	  Swig_mark_arg(i);
	} else if (strcmp(argv[i], "-fastunpack") == 0) {
	  fastunpack = 1;
	  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], "-nofastproxy") == 0) {
	  fastproxy = 0;
	  Swig_mark_arg(i);
	} else if (strcmp(argv[i], "-fastquery") == 0) {
	  fastquery = 1;
	  Swig_mark_arg(i);
	} else if (strcmp(argv[i], "-nofastquery") == 0) {
	  fastquery = 0;
	  Swig_mark_arg(i);
	} else if (strcmp(argv[i], "-fastinit") == 0) {
	  fastinit = 1;
	  Swig_mark_arg(i);
	} else if (strcmp(argv[i], "-nofastinit") == 0) {
	  fastinit = 0;
	  Swig_mark_arg(i);
	} else if (strcmp(argv[i], "-olddefs") == 0) {
	  olddefs = 1;
	  Swig_mark_arg(i);
	} else if (strcmp(argv[i], "-noolddefs") == 0) {
	  olddefs = 0;
	  Swig_mark_arg(i);
	} else if (strcmp(argv[i], "-castmode") == 0) {
	  castmode = 1;
	  Swig_mark_arg(i);
	} else if (strcmp(argv[i], "-nocastmode") == 0) {
	  castmode = 0;
	  Swig_mark_arg(i);
	} else if (strcmp(argv[i], "-extranative") == 0) {
	  extranative = 1;
	  Swig_mark_arg(i);
	} else if (strcmp(argv[i], "-noextranative") == 0) {
	  extranative = 0;
	  Swig_mark_arg(i);
	} else if (strcmp(argv[i], "-modernargs") == 0) {
	  modernargs = 1;
	  Swig_mark_arg(i);
	} else if (strcmp(argv[i], "-nomodernargs") == 0) {
	  modernargs = 0;
	  Swig_mark_arg(i);
	} else if (strcmp(argv[i], "-aliasobj0") == 0) {
	  aliasobj0 = 1;
	  Swig_mark_arg(i);
	} else if (strcmp(argv[i], "-noaliasobj0") == 0) {
	  aliasobj0 = 0;
	  Swig_mark_arg(i);
	} else if (strcmp(argv[i], "-proxydel") == 0) {
	  proxydel = 1;
	  Swig_mark_arg(i);
	} else if (strcmp(argv[i], "-noproxydel") == 0) {
	  proxydel = 0;
	  Swig_mark_arg(i);
	} else if (strcmp(argv[i], "-modern") == 0) {
	  classic = 0;
	  modern = 1;
	  modernargs = 1;
	  Swig_mark_arg(i);
	} else if (strcmp(argv[i], "-nomodern") == 0) {
	  modern = 0;
	  modernargs = 0;
	  Swig_mark_arg(i);
	} else if (strcmp(argv[i], "-noh") == 0) {
	  no_header_file = 1;
	  Swig_mark_arg(i);
	} else if ((strcmp(argv[i], "-new_vwm") == 0) || (strcmp(argv[i], "-newvwm") == 0)) {
	  /* Turn on new value wrapper mpde */
	  Swig_value_wrapper_mode(1);
	  no_header_file = 1;
	  Swig_mark_arg(i);
	} else if (strcmp(argv[i], "-O") == 0) {
	  classic = 0;
	  modern = 1;
	  safecstrings = 0;
	  buildnone = 0;
	  nobuildnone = 1;
	  classptr = 0;
	  proxydel = 0;
	  fastunpack = 1;
	  fastproxy = 1;
	  fastinit = 1;
	  fastquery = 1;
	  modernargs = 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], "-py3") == 0) {
      py3 = 1;
      Swig_mark_arg(i);
    }
      
      }
    } /* for */

    if (py3) {
        /* force disable features that not compatible with Python 3.x */
        classic = 0;
    }

    if (cppcast) {
      Preprocessor_define((DOH *) "SWIG_CPLUSPLUS_CAST", 0);
    }

    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;
    {
      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")) {
	    castmode = 0;
	  }
	  if (Getattr(options, "extranative")) {
	    extranative = 1;
	  }
	  if (Getattr(options, "noextranative")) {
	    extranative = 0;
	  }
	  if (Getattr(options, "outputtuple")) {
	    outputtuple = 1;
	  }
	  if (Getattr(options, "nooutputtuple")) {
	    outputtuple = 0;
	  }
	  mod_docstring = Getattr(options, "docstring");
	  package = Getattr(options, "package");
	}
      }
    }

    /* 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);
      SWIG_exit(EXIT_FAILURE);
    }
    f_runtime = NewString("");
    f_init = NewString("");
    f_header = NewString("");
    f_wrappers = NewString("");
    f_directors_h = NewString("");
    f_directors = NewString("");

    if (directorsEnabled()) {
      if (!no_header_file) {
	f_runtime_h = NewFile(outfile_h, "w", SWIG_output_files());
	if (!f_runtime_h) {
	  FileErrorDisplay(outfile_h);
	  SWIG_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("");

    Swig_banner(f_begin);

    Printf(f_runtime, "\n");
    Printf(f_runtime, "#define SWIGPYTHON\n");

    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 (safecstrings) {
      Printf(f_runtime, "#define SWIG_PYTHON_SAFE_CSTRINGS\n");
    }

    if (buildnone) {
      Printf(f_runtime, "#define SWIG_PYTHON_BUILD_NONE\n");
    }

    if (nobuildnone) {
      Printf(f_runtime, "#define SWIG_PYTHON_NO_BUILD_NONE\n");
    }

    if (!dirvtable) {
      Printf(f_runtime, "#define SWIG_PYTHON_DIRECTOR_NO_VTABLE\n");
    }

    if (outputtuple) {
      Printf(f_runtime, "#define SWIG_PYTHON_OUTPUT_TUPLE\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 (classic) {
      Printf(f_runtime, "#define SWIG_PYTHON_CLASSIC\n");
    }

    Printf(f_runtime, "\n");

    Printf(f_header, "#if (PY_VERSION_HEX <= 0x02000000)\n");
    Printf(f_header, "# if !defined(SWIG_PYTHON_CLASSIC)\n");
    Printf(f_header, "#  error \"This python version requires swig to be run with the '-classic' option\"\n");
    Printf(f_header, "# endif\n");
    Printf(f_header, "#endif\n");

    if (modern) {
      Printf(f_header, "#if (PY_VERSION_HEX <= 0x02020000)\n");
      Printf(f_header, "# error \"This python version requires swig to be run with the '-nomodern' option\"\n");
      Printf(f_header, "#endif\n");
    }

    if (modernargs) {
      Printf(f_header, "#if (PY_VERSION_HEX <= 0x02020000)\n");
      Printf(f_header, "# error \"This python version requires swig to be run with the '-nomodernargs' option\"\n");
      Printf(f_header, "#endif\n");
    }

    if (fastunpack) {
      Printf(f_header, "#ifndef METH_O\n");
      Printf(f_header, "# error \"This python version requires swig to be run with the '-nofastunpack' option\"\n");
      Printf(f_header, "#endif\n");
    }

    if (fastquery) {
      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)
	Printf(f_directors, "#include \"%s\"\n\n", Swig_file_filename(outfile_h));
    }

    /* If shadow classing is enabled, we're going to change the module name to "_module" */
    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);
	SWIG_exit(EXIT_FAILURE);
      }
      Delete(filen);
      filen = NULL;

      f_shadow = NewString("");
      f_shadow_imports = NewString("");
      f_shadow_stubs = NewString("");

      Swig_register_filebyname("shadow", f_shadow);
      Swig_register_filebyname("python", f_shadow);

      Swig_banner_target_lang(f_shadow, "#");

      if (!modern) {
	Printv(f_shadow, "# This file is compatible with both classic and new-style classes.\n", NIL);
      }

      if (mod_docstring && Len(mod_docstring)) {
	Printv(f_shadow, "\n\"\"\"\n", mod_docstring, "\n\"\"\"\n", NIL);
	Delete(mod_docstring);
	mod_docstring = NULL;
      }

      Printv(f_shadow, "\nfrom sys import version_info\n", NULL);

      if(fastproxy)
      {
        Printv(f_shadow, "if version_info >= (3,0,0):\n", NULL);
        Printf(f_shadow, tab4 "new_instancemethod = lambda func, inst, cls: %s.SWIG_PyInstanceMethod_New(func)\n", module);
        Printv(f_shadow, "else:\n", NULL);
        Printv(f_shadow, tab4, "from new import instancemethod as new_instancemethod\n", NULL);
      }
      /* Import the C-extension 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 C-extension is on
       * sys.path.  Relative imports must be explicitly specified from 2.6.0
       * onwards (implicit relative imports will raise a DeprecationWarning
       * in 2.6, and fail in 2.7 onwards), but the relative import syntax
       * isn't available in python 2.4 or earlier, so we have to write some
       * code conditional on the python version.
       */
      Printv(f_shadow, "if version_info >= (2,6,0):\n", NULL);
      Printv(f_shadow, tab4, "def swig_import_helper():\n", NULL);
      Printv(f_shadow, tab8, "from os.path import dirname\n", NULL);
      Printv(f_shadow, tab8, "import imp\n", NULL);
      Printv(f_shadow, tab8, "fp = None\n", NULL);
      Printv(f_shadow, tab8, "try:\n", NULL);
      Printf(f_shadow, tab4 tab8 "fp, pathname, description = imp.find_module('%s', [dirname(__file__)])\n", module);
      Printf(f_shadow, tab8 "except ImportError:\n");
      /* At here, the module may already loaded, so simply import it. */
      Printf(f_shadow, tab4 tab8 "import %s\n", module);
      Printf(f_shadow, tab4 tab8 "return %s\n", module);
      Printv(f_shadow, tab8 "if fp is not None:\n", NULL);
      Printv(f_shadow, tab4 tab8 "try:\n", NULL);
      Printf(f_shadow, tab8 tab8 "_mod = imp.load_module('%s', fp, pathname, description)\n", module);
      Printv(f_shadow, tab4 tab8, "finally:\n", NULL);
      Printv(f_shadow, tab8 tab8, "fp.close()\n", NULL);
      Printv(f_shadow, tab4 tab8, "return _mod\n", NULL);
      Printf(f_shadow, tab4 "%s = swig_import_helper()\n", module);
      Printv(f_shadow, tab4, "del swig_import_helper\n", NULL);
      Printv(f_shadow, "else:\n", NULL);
      Printf(f_shadow, tab4 "import %s\n", module);

      /* Delete the version_info symbol since we don't use it elsewhere in the
       * module. */
      Printv(f_shadow, "del version_info\n", NULL);

      if (modern || !classic) {
	Printv(f_shadow, "try:\n", tab4, "_swig_property = property\n", "except NameError:\n", tab4, "pass # Python < 2.2 doesn't have 'property'.\n", NULL);
      } 
      /* if (!modern) */
      /* always needed, a class can be forced to be no-modern, such as an exception */
      {
	// Python-2.2 object hack
	Printv(f_shadow,
	       "def _swig_setattr_nondynamic(self,class_type,name,value,static=1):\n",
	       tab4, "if (name == \"thisown\"): return self.this.own(value)\n",
	       tab4, "if (name == \"this\"):\n", tab4, tab4, "if type(value).__name__ == 'SwigPyObject':\n", tab4, tab8, "self.__dict__[name] = value\n",
#ifdef USE_THISOWN
	       tab4, tab8, "if hasattr(value,\"thisown\"): self.__dict__[\"thisown\"] = value.thisown\n", tab4, tab8, "del value.thisown\n",
#endif
	       tab4, tab8, "return\n", tab4, "method = class_type.__swig_setmethods__.get(name,None)\n", tab4, "if method: return method(self,value)\n",
#ifdef USE_THISOWN
	       tab4, "if (not static) or hasattr(self,name) or (name == \"thisown\"):\n",
#else
	       tab4, "if (not static) or hasattr(self,name):\n",
#endif
	       tab4, tab4, "self.__dict__[name] = value\n",
	       tab4, "else:\n",
	       tab4, tab4, "raise AttributeError(\"You cannot add attributes to %s\" % self)\n\n",
	       "def _swig_setattr(self,class_type,name,value):\n", tab4, "return _swig_setattr_nondynamic(self,class_type,name,value,0)\n\n", NIL);

	Printv(f_shadow,
	       "def _swig_getattr(self,class_type,name):\n",
	       tab4, "if (name == \"thisown\"): return self.this.own()\n",
	       tab4, "method = class_type.__swig_getmethods__.get(name,None)\n",
	       tab4, "if method: return method(self)\n", tab4, "raise AttributeError(name)\n\n", NIL);

	Printv(f_shadow,
	       "def _swig_repr(self):\n",
	       tab4, "try: strthis = \"proxy of \" + self.this.__repr__()\n",
	       tab4, "except: strthis = \"\"\n", tab4, "return \"<%s.%s; %s >\" % (self.__class__.__module__, self.__class__.__name__, strthis,)\n\n", NIL);

	if (!classic) {
          /* Usage of types.ObjectType is deprecated.
           * But don't sure wether this would broken old Python?
           */
	  Printv(f_shadow,
//		 "import types\n",
		 "try:\n",
//		 "    _object = types.ObjectType\n",
		 "    _object = object\n",
		 "    _newclass = 1\n", "except AttributeError:\n", "    class _object : pass\n", "    _newclass = 0\n", 
//                 "del types\n", 
                 "\n\n", NIL);
	}
      }
      if (modern) {
	Printv(f_shadow, "def _swig_setattr_nondynamic_method(set):\n", tab4, "def set_attr(self,name,value):\n",
#ifdef USE_THISOWN
	       tab4, tab4, "if hasattr(self,name) or (name in (\"this\", \"thisown\")):\n",
#else
	       tab4, tab4, "if (name == \"thisown\"): return self.this.own(value)\n", tab4, tab4, "if hasattr(self,name) or (name == \"this\"):\n",
#endif
	       tab4, tab4, tab4, "set(self,name,value)\n",
	       tab4, tab4, "else:\n",
	       tab4, tab4, tab4, "raise AttributeError(\"You cannot add attributes to %s\" % self)\n", tab4, "return set_attr\n\n\n", NIL);
      }

      if (directorsEnabled()) {
	// Try loading weakref.proxy, which is only available in Python 2.1 and higher
	Printv(f_shadow,
	       "try:\n", tab4, "import weakref\n", tab4, "weakref_proxy = weakref.proxy\n", "except:\n", tab4, "weakref_proxy = lambda x: x\n", "\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");

    /* the method exported for replacement of new.instancemethod in Python 3 */
    add_pyinstancemethod_new();

    /* 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.swg", f_runtime);
    }

    /* Close language module */
    Append(methods, "\t { NULL, NULL, 0, NULL }\n");
    Append(methods, "};\n");
    Printf(f_wrappers, "%s\n", methods);

    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);
    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) {
      Printv(f_shadow_py, f_shadow, "\n", NIL);
      Printv(f_shadow_py, f_shadow_stubs, "\n", NIL);

      Close(f_shadow_py);
      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)
	Close(f_runtime_h);
      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);

    Close(f_begin);
    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()
  {
    String* name = NewString("SWIG_PyInstanceMethod_New");
    Printf(methods, "\t { (char *)\"%s\", (PyCFunction)%s, METH_O, NULL},\n", name, name);
    Delete(name);
    return 0;
  }

  /* ------------------------------------------------------------
   * importDirective()
   * ------------------------------------------------------------ */

  virtual int importDirective(Node *n) {
    if (shadow) {
      String *modname = Getattr(n, "module");

      if (modname) {
	String *import = NewString("import ");

	// 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);

	// 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 *options = Getattr(mod, "options");
	String *pkg = options ? Getattr(options, "package") : 0;
	if (pkg && (!package || Strcmp(pkg, package) != 0)) {
	  Printf(import, "%s.", pkg);
	}
	// finally, output the name of the imported module
	if (shadowimport) {
	  if (!options || (!Getattr(options, "noshadow") && !Getattr(options, "noproxy"))) {
	    Printf(import, "_%s\n", modname);
	    if (!Strstr(f_shadow_imports, import)) {
	      if (pkg && (!package || Strcmp(pkg, package) != 0)) {
	        Printf(f_shadow, "import %s.%s\n", pkg, modname);
	      } else {
	        Printf(f_shadow, "import %s\n", modname);
	      }
	      Printv(f_shadow_imports, import, NULL);
	    }
	  }
	}

	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;
   }


  /* ------------------------------------------------------------
   * pythoncode()     - Output python code into the shadow file
   * ------------------------------------------------------------ */

  String *pythoncode(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 = DohSplitLines(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;
  }


  /* ------------------------------------------------------------
   * 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;
    if (autodoc) {
      char *c = Char(autodoc);
      if (c && 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 neccessary,
   *    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 use_triple = true) {
    String *str = Getattr(n, "feature:docstring");
    bool have_ds = (str && Len(str) > 0);
    bool have_auto = (Getattr(n, "feature:autodoc") && !GetFlag(n, "feature:noautodoc"));
    const char *triple_double = use_triple ? "\"\"\"" : "";
    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 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 (have_auto && have_ds) {	// Both autodoc and docstring are present
      doc = NewString("");
      Printv(doc, triple_double, "\n", pythoncode(autodoc, indent), "\n", pythoncode(str, indent), indent, triple_double, NIL);
    } else if (!have_auto && have_ds) {	// only docstring
      if (Strchr(str, '\n') == 0) {
	doc = NewStringf("%s%s%s", triple_double, str, triple_double);
      } else {
	doc = NewString("");
	Printv(doc, triple_double, "\n", pythoncode(str, indent), indent, triple_double, NIL);
      }
    } else if (have_auto && !have_ds) {	// only autodoc
      if (Strchr(autodoc, '\n') == 0) {
	doc = NewStringf("%s%s%s", triple_double, autodoc, triple_double);
      } else {
	doc = NewString("");
	Printv(doc, triple_double, "\n", pythoncode(autodoc, indent), indent, triple_double, NIL);
      }
    } else
      doc = NewString("");

    // Save the generated strings in the parse tree in case they are used later
    // by post processing tools
    Setattr(n, "python:docstring", doc);
    Setattr(n, "python:autodoc", autodoc);
    return doc;
  }

   /* -----------------------------------------------------------------------------
   * makeParameterName()
   *    Note: the generated name should consist with that in kwnames[]
   *
   * Inputs: 
   *   n - Node
   *   p - parameter node
   *   arg_num - parameter argument number
   * Return:
   *   arg - a unique parameter name
   * ----------------------------------------------------------------------------- */

  String *makeParameterName(ParmList *plist, Parm *p, int arg_num) {
    String *arg = 0;
    String *pn = Swig_name_make(p, 0, Getattr(p, "name"), 0, 0);
    // Use C parameter name unless it is a duplicate or an empty parameter name
    int count = 0;
    if ( SwigType_isvarargs(Getattr(p, "type")) ) {
      return NewString("*args");
    }
    while (plist) {
      if ((Cmp(pn, Getattr(plist, "name")) == 0))
        count++;
      plist = nextSibling(plist);
    }
    arg = (!pn || !Len(pn) || (count > 1)) ? NewStringf("arg%d", arg_num) : Copy(pn);
    return arg;
  }


  /* ------------------------------------------------------------
   * make_autodocParmList()
   *   Generate the documentation for the function parameters
   *   Parameters:
   *    func_annotation: Function annotation support
   * ------------------------------------------------------------ */

  String *make_autodocParmList(Node *n, bool showTypes, bool calling=false, bool func_annotation=false) {

 
    String *doc = NewString("");
    String *pdocs = Copy(Getattr(n, "feature:pdocs"));
    ParmList *plist = CopyParmList(Getattr(n, "parms"));
    Parm *p;
    Parm *pnext;
    Node *lookup; 


    int lines = 0;
    int arg_num = 0;
    const int maxwidth = 50;

    if(calling)
      func_annotation = false;
    
    if (pdocs)
      Append(pdocs, "\n");

    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 *ptype = 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");
	ptype = Getattr(p, "tmap:doc:pytype");
      }

      name = name ? name : Getattr(p, "name");
      type = type ? type : Getattr(p, "type");
      value = value ? value : Getattr(p, "value");

      name = makeParameterName(plist, p, arg_num);
      // Reset it for convinient in further use. (mainly for makeParameterName())
      // Since the plist is created by CopyParmList,
      // we can hope that the set would have no side effect
      Setattr(p, "name", name);

      arg_num++;


      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;
	}
      }
      
      type = SwigType_base(type);
      lookup = Swig_symbol_clookup(type, 0);
      if (lookup)
        type = Getattr(lookup, "sym:name");
      
      // Do the param type too?
      if (showTypes)
        Printf(doc, "%s ", type);

      
      Append(doc, name);
      if (pdoc) {
        if (!pdocs)
          pdocs = NewString("Parameters:\n");
        Printf(pdocs, "   %s\n", pdoc);
      }

      // Write the function annoation
      if (func_annotation)
        Printf(doc, " : '%s'", type);

      // Write default value
      if (value && !calling) {
        String* pv = pyvalue(value, Getattr(p, "type"));
        if (pv)
          value = pv;
	else {
	  lookup = Swig_symbol_clookup(value, 0);
	  if (lookup) {
	    value = Getattr(lookup, "sym:name");
          }
	}
	Printf(doc, " = %s", value);        
      }
    }
    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 funciton 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) {
	String *symname = Getattr(n, "sym:name");
	SwigType *type = Getattr(n, "type");

	if (type) {
	  if (Strcmp(type, "void") == 0)
	    type = NULL;
	  else {
	    type = SwigType_base(type);
	    Node *lookup = Swig_symbol_clookup(type, 0);
	    if (lookup)
	      type = Getattr(lookup, "sym:name");
	  }
	}

	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 (CPlusPlus) {
		Printf(doc, "Proxy of C++ %s class", real_classname);
	      } else {
		Printf(doc, "Proxy of C %s struct", real_classname);
	      }
	    }
	  }
	  break;
	case AUTODOC_CTOR:
	  if (Strcmp(class_name, symname) == 0) {
	    String *paramList = make_autodocParmList(n, showTypes);
	    if (Len(paramList))
	      Printf(doc, "__init__(self, %s) -> %s", paramList, class_name);
	    else
	      Printf(doc, "__init__(self) -> %s", class_name);
	  } else
	    Printf(doc, "%s(%s) -> %s", symname, make_autodocParmList(n, showTypes), class_name);
	  break;

	case AUTODOC_DTOR:
	  Append(doc, "__del__(self)");
	  break;

	case AUTODOC_STATICFUNC:
	  Printf(doc, "%s(%s)", symname, make_autodocParmList(n, showTypes));
	  if (type)
	    Printf(doc, " -> %s", type);
	  break;

	case AUTODOC_FUNC:
	  Printf(doc, "%s(%s)", symname, make_autodocParmList(n, showTypes));
	  if (type)
	    Printf(doc, " -> %s", type);
	  break;

	case AUTODOC_METHOD:
	  String *paramList = make_autodocParmList(n, showTypes);
	  if (Len(paramList))
	    Printf(doc, "%s(self, %s)", symname, paramList);
	  else
	    Printf(doc, "%s(self)", symname);
	  if (type)
	    Printf(doc, " -> %s", type);
	  break;
	}
      }
      if (extended) {
	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)
	Append(doc, "\n");
    }

    return doc;
  }
  
  /* ------------------------------------------------------------
   * pyvalue()
   *    Check if string v can be a Python value literal,
   *    (eg. number or string), or translate it to a Python literal.
   * ------------------------------------------------------------ */
  String* pyvalue(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, "true")==0 || Strcmp(v, "FALSE")==0)
        return NewString("True");
      if (Strcmp(v, "false")==0 || Strcmp(v, "FALSE")==0)
        return NewString("False");
      if (Strcmp(v, "NULL")==0)
        return NewString("None");
    }
    return 0;
  }
  /* ------------------------------------------------------------
   * is_primitive_defaultargs()
   *    Check if all the default args have primitive type.
   *    (So we can generate proper parameter list with default 
   *    values..)
   * ------------------------------------------------------------ */
  bool is_primitive_defaultargs(Node *n)
  {
    ParmList *plist = CopyParmList(Getattr(n, "parms"));
    Parm *p;
    Parm *pnext;

    Swig_typemap_attach_parms("in", plist, 0);
    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 *type = Getattr(p, "type");
      String *value = Getattr(p, "value");
      if (!pyvalue(value, type))
        return false;
    }
    return true;
  }


  /* ------------------------------------------------------------
   * is_real_overloaded()
   *   Check if the function is overloaded, but not just have some
   *   siblings generated due to the original function have 
   *   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)
  {
    /* Get the original function for a defaultargs copy, 
     * see default_arguments() in parser.y. */
    Node *nn = Getattr(n, "defaultargs");
    if (nn) n = nn;

    /* For overloaded function, just use *args */
    if (is_real_overloaded(n) ||
        GetFlag(n, "feature:compactdefaultargs") ||
        !is_primitive_defaultargs(n))
    {
      String *parms = NewString("");
      if(in_class)
        Printf(parms, "self, ");
      Printf(parms, "*args");
      if (kw)
        Printf(parms, ", **kwargs");
      return parms;
    }

    bool funcanno = py3 ? true : false;
    String *params = NewString("");
    String *_params = make_autodocParmList(n, false, 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 neccessary
   * ------------------------------------------------------------ */

  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 neccessary
   * ------------------------------------------------------------ */

  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) || have_docstring(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);
    }
    return (ret && py3) ? NewStringf(" -> \"%s\" ", ret)
                        : NewString("");
  }

  /* ------------------------------------------------------------
   * 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);
    /* Make a wrapper function to insert the code into */
    Printv(f_dest, "\ndef ", name, "(", parms, ")", returnTypeAnnotation(n), ":\n", NIL);
    if (have_docstring(n))
      Printv(f_dest, "  ", docstring(n, AUTODOC_FUNC, tab4), "\n", NIL);
    if (have_pythonprepend(n))
      Printv(f_dest, pythoncode(pythonprepend(n), "  "), "\n", NIL);
    if (have_pythonappend(n)) {
      Printv(f_dest, "  val = ", funcCall(name, callParms), "\n", NIL);
      Printv(f_dest, pythoncode(pythonappend(n), "  "), "\n", NIL);
      Printv(f_dest, "  return val\n", NIL);
    } else {
	Printv(f_dest, "  return ", funcCall(name, callParms), "\n", NIL);
    }

    if (Getattr(n, "feature:python:callback") || !have_addtofunc(n)) {
      /* 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) {
    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) {
    if (!kw) {
      if (n && funpack) {
	if (num_required == 0 && num_arguments == 0) {
	  Printf(methods, "\t { (char *)\"%s\", (PyCFunction)%s, METH_NOARGS, ", name, function);
	} else if (num_required == 1 && num_arguments == 1) {
	  Printf(methods, "\t { (char *)\"%s\", (PyCFunction)%s, METH_O, ", name, function);
	} else {
	  Printf(methods, "\t { (char *)\"%s\", %s, METH_VARARGS, ", name, function);
	}
      } else {
	Printf(methods, "\t { (char *)\"%s\", %s, METH_VARARGS, ", name, function);
      }
    } else {
      Printf(methods, "\t { (char *)\"%s\", (PyCFunction) %s, METH_VARARGS | METH_KEYWORDS, ", name, function);
    }

    if (!n) {
      Append(methods, "NULL");
    } else if (Getattr(n, "feature:callback")) {
      if (have_docstring(n)) {
	String *ds = docstring(n, AUTODOC_FUNC, "", false);
	Replaceall(ds, "\\", "\\\\");
	Replaceall(ds, "\"", "\\\"");
	Replaceall(ds, "\n", "\\n\"\n\t\t\"");
	Printf(methods, "(char *)\"%s\\nswig_ptr: %s\"", ds, Getattr(n, "feature:callback:name"));
      } else {
	Printf(methods, "(char *)\"swig_ptr: %s\"", Getattr(n, "feature:callback:name"));
      }
    } else if (have_docstring(n)) {
      String *ds = docstring(n, AUTODOC_FUNC, "", false);
      Replaceall(ds, "\\", "\\\\");
      Replaceall(ds, "\"", "\\\"");
      Replaceall(ds, "\n", "\\n\"\n\t\t\"");
      Printf(methods, "(char *)\"%s\"", ds);
    } else {
      Append(methods, "NULL");
    }

    Append(methods, "},\n");
  }

  /* ------------------------------------------------------------
   * dispatchFunction()
   * ------------------------------------------------------------ */
  void dispatchFunction(Node *n, int funpack = 0) {
    /* Last node in overloaded chain */

    int maxargs;

    String *tmp = NewString("");
    String *dispatch;
    const char *dispatch_code = funpack ? "return %s(self, argc, argv);" : "return %s(self, args);";

    if (castmode) {
      dispatch = Swig_overload_dispatch_cast(n, dispatch_code, &maxargs);
    } else {
      dispatch = Swig_overload_dispatch(n, dispatch_code, &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 PyObject *", wname, "(PyObject *self, PyObject *args) {", NIL);

    Wrapper_add_local(f, "argc", "int argc");
    Printf(tmp, "PyObject *argv[%d]", maxargs + 1);
    Wrapper_add_local(f, "argv", tmp);

    if (!fastunpack) {
      Wrapper_add_local(f, "ii", "int ii");
      Append(f->code, "if (!PyTuple_Check(args)) SWIG_fail;\n");
      Append(f->code, "argc = (int)PyObject_Length(args);\n");
      Printf(f->code, "for (ii = 0; (ii < argc) && (ii < %d); ii++) {\n", maxargs);
      Append(f->code, "argv[ii] = PyTuple_GET_ITEM(args,ii);\n");
      Append(f->code, "}\n");
    } else {
      String *iname = Getattr(n, "sym:name");
      Printf(f->code, "if (!(argc = SWIG_Python_UnpackTuple(args,\"%s\",0,%d,argv))) SWIG_fail;\n", iname, maxargs);
      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 {
	Printf(protoTypes, "\n\"    %s(%s)\\n\"", SwigType_str(Getattr(sibl, "name"), 0), ParmList_protostr(Getattr(sibl, "wrap:parms")));
      } while ((sibl = Getattr(sibl, "sym:nextSibling")));
      Append(f->code, "fail:\n");
      Printf(f->code, "SWIG_SetErrorMsg(PyExc_NotImplementedError,"
	     "\"Wrong number or type of arguments for overloaded function '%s'.\\n\"" "\n\"  Possible C/C++ prototypes are:\\n\"%s);\n", symname, protoTypes);
      Append(f->code, "return NULL;\n");
      Delete(protoTypes);
    }
    Printv(f->code, "}\n", NIL);
    Wrapper_print(f, f_wrappers);
    Node *p = Getattr(n, "sym:previousSibling");
    add_method(symname, wname, 0, p);

    /* Create a shadow for this function (if enabled and not in a member function) */
    if ((shadow) && (!(shadow & PYSHADOW_MEMBER))) {
      emitFunctionShadowHelper(n, f_shadow_stubs, symname, 0);
    }
    DelWrapper(f);
    Delete(dispatch);
    Delete(tmp);
    Delete(wname);
  }

  /* ------------------------------------------------------------
   * functionWrapper()
   * ------------------------------------------------------------ */


  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");
    int director_method = 0;

    Parm *p;
    int i;
    char source[64];
    Wrapper *f;
    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 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);
    }


    if (Getattr(n, "sym:overloaded")) {
      overname = Getattr(n, "sym:overname");
    } else {
      if (!addSymbol(iname, n))
	return SWIG_ERROR;
    }

    f = NewWrapper();
    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 */
    num_arguments = emit_num_arguments(l);
    num_required = emit_num_required(l);
    if (((num_arguments == 0) && (num_required == 0)) || ((num_arguments == 1) && (num_required == 1) && Getattr(l, "self")))
      allow_kwargs = 0;
    varargs = emit_isvarargs(l);

    String *wname = Swig_name_wrapper(iname);
    if (overname) {
      Append(wname, overname);
    }

    if (!allow_kwargs || Getattr(n, "sym:overloaded")) {
      if (!varargs) {
	Printv(f->def, "SWIGINTERN PyObject *", wname, "(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {", NIL);
      } else {
	Printv(f->def, "SWIGINTERN PyObject *", wname, "__varargs__", "(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *varargs) {", 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, "SWIGINTERN PyObject *", wname, "(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {", NIL);
    }
    if (!allow_kwargs) {
      Append(parse_args, "    if (!PyArg_ParseTuple(args,(char *)\"");
    } else {
      Append(parse_args, "    if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)\"");
      Append(arglist, ",kwnames");
    }

    int funpack = modernargs && fastunpack && !varargs && !allow_kwargs;
    int noargs = funpack && (num_required == 0 && num_arguments == 0);
    int onearg = funpack && (num_required == 1 && num_arguments == 1);

    /* Generate code for argument marshalling */
    if (funpack) {
      if (overname) {
	if (aliasobj0) {
	  Append(f->code, "#define obj0 (swig_obj[0])\n");
	}
      } else if (num_arguments) {
	sprintf(source, "PyObject *swig_obj[%d]", num_arguments);
	Wrapper_add_localv(f, "swig_obj", source, NIL);
	if (aliasobj0) {
	  Append(f->code, "#define obj0 (swig_obj[0])\n");
	}
      }
    }


    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);
	}
      }
    }

    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 *pn = Getattr(p, "name");
      String *ln = Getattr(p, "lname");
      if (funpack) {
	sprintf(source, "swig_obj[%d]", i);
      } else {
	sprintf(source, "obj%d", i);
      }


      Putc(',', arglist);
      if (i == num_required)
	Putc('|', parse_args);	/* Optional argument separator */

      /* Keyword argument handling */
      if (allow_kwargs) {
	if (Len(pn)) {
	  String *tmp = 0;
	  String *name = pn;
	  if (!Getattr(p,"hidden")) {
	    name = tmp = Swig_name_make(p, 0, pn, 0, 0);
	  }
	  Printf(kwargs, "(char *) \"%s\",", name);
	  if (tmp)
	    Delete(tmp);
	} else {
	  Printf(kwargs, "(char *)\"arg%d\",", i + 1);
	}
      }

      /* Look for an input typemap */
      if ((tm = Getattr(p, "tmap:in"))) {
	String *parse = Getattr(p, "tmap:in:parse");
	if (!parse) {
	  if (funpack) {
	    Replaceall(tm, "$self", "swig_obj[0]");
	  } else {
	    Replaceall(tm, "$self", "obj0");
	  }
	  Replaceall(tm, "$source", source);
	  Replaceall(tm, "$target", ln);
	  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);
	  }

	  Putc('O', parse_args);
	  if (!funpack) {
	    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);
	  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 || !modernargs) {
      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, "SWIGINTERN PyObject *", wname, "(PyObject *SWIGUNUSEDPARM(self), int nobjs, PyObject **SWIGUNUSEDPARM(swig_obj)) {", NIL);
	  } else {
	    Printv(f->def, "SWIGINTERN PyObject *", wname, "(PyObject *SWIGUNUSEDPARM(self), int nobjs, PyObject **swig_obj) {", NIL);
	  }
	  Printf(parse_args, "if ((nobjs < %d) || (nobjs > %d)) SWIG_fail;\n", num_required, num_arguments);
	} else {
	  if (noargs) {
	    Printv(f->def, "SWIGINTERN PyObject *", wname, "(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {", NIL);
	  } else {
	    Printv(f->def, "SWIGINTERN PyObject *", wname, "(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {", NIL);
	  }
	  if (onearg) {
	    Printf(parse_args, "if (!args) SWIG_fail;\n");
	    Printf(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_required, num_arguments);
	  } else if (noargs) {
	    Printf(parse_args, "if (!SWIG_Python_UnpackTuple(args,\"%s\",%d,%d,0)) SWIG_fail;\n", iname, num_required, num_arguments);
	  }
	}
      } else {
	Printf(parse_args, "if(!PyArg_UnpackTuple(args,(char *)\"%s\",%d,%d", iname, num_required, num_arguments);
	Printv(parse_args, arglist, ")) SWIG_fail;\n", NIL);
      }
    }

    /* Now piece together the first part of the wrapper function */
    Printv(f->code, 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"))) {
	Replaceall(tm, "$target", Getattr(p, "lname"));
	Printv(f->code, tm, "\n", NIL);
	p = Getattr(p, "tmap:check:next");
      } else {
	p = nextSibling(p);
      }
    }

    /* Insert cleanup code */
    for (p = l; p;) {
      //      if (!checkAttribute(p,"tmap:in:numinputs","0") && !Getattr(p,"tmap:in:parse")) {
      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)) {
	  Replaceall(tm, "$source", Getattr(p, "lname"));
	  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, "$source", Getattr(p, "lname"));
	Replaceall(tm, "$target", "resultobj");
	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) {
	Append(f->code, "upcall = (director && (director->swig_get_self()==swig_obj[0]));\n");
      } else {
	Append(f->code, "upcall = (director && (director->swig_get_self()==obj0));\n");
      }
    }

    /* 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 */
    if ((tm = Swig_typemap_lookup_out("out", n, "result", f, actioncode))) {
      if (funpack) {
	Replaceall(tm, "$self", "swig_obj[0]");
      } else {
	Replaceall(tm, "$self", "obj0");
      }
      Replaceall(tm, "$source", "result");
      Replaceall(tm, "$target", "resultobj");
      Replaceall(tm, "$result", "resultobj");
      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");
	}
      }
      // FIXME: this will not try to unwrap directors returned as non-director
      //        base class pointers!

      /* New addition to unwrap director return values so that the original
       * python object is returned instead. 
       */
#if 1
      int unwrap = 0;
      String *decl = Getattr(n, "decl");
      int is_pointer = SwigType_ispointer_return(decl);
      int is_reference = SwigType_isreference_return(decl);
      if (is_pointer || is_reference) {
	String *type = Getattr(n, "type");
	//Node *classNode = Swig_methodclass(n);
	//Node *module = Getattr(classNode, "module");
	Node *parent = Swig_methodclass(n);
	Node *module = Getattr(parent, "module");
	Node *target = Swig_directormap(module, type);
	if (target)
	  unwrap = 1;
      }
      if (unwrap) {
	Wrapper_add_local(f, "director", "Swig::Director *director = 0");
	Append(f->code, "director = SWIG_DIRECTOR_CAST(result);\n");
	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);
      }
#else
      Printf(f->code, "%s\n", tm);
#endif
      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, "result", 0))) {
	Replaceall(tm, "$source", "result");
	Printf(f->code, "%s\n", tm);
	Delete(tm);
      }
    }

    /* See if there is any return cleanup code */
    if ((tm = Swig_typemap_lookup("ret", n, "result", 0))) {
      Replaceall(tm, "$source", "result");
      Printf(f->code, "%s\n", tm);
      Delete(tm);
    }

    if (director_method) {
      if ((tm = Swig_typemap_lookup("directorfree", n, "result", 0))) {
	Replaceall(tm, "$input", "result");
	Replaceall(tm, "$result", "resultobj");
	Printf(f->code, "%s\n", tm);
	Delete(tm);
      }
    }

    Append(f->code, "    return resultobj;\n");

    /* Error handling code */

    Append(f->code, "fail:\n");
    if (need_cleanup) {
      Printv(f->code, cleanup, NIL);
    }
    Printv(f->code, "  return NULL;\n", NIL);


    if (funpack) {
      if (aliasobj0) {
	Append(f->code, "#if defined(obj0)\n");
	Append(f->code, "#undef obj0\n");
	Append(f->code, "#endif\n");
      }
    }


    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 (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();
      Printv(f->def, "SWIGINTERN PyObject *", wname, "(PyObject *self, PyObject *args) {", NIL);
      Wrapper_add_local(f, "resultobj", "PyObject *resultobj");
      Wrapper_add_local(f, "varargs", "PyObject *varargs");
      Wrapper_add_local(f, "newargs", "PyObject *newargs");
      Printf(f->code, "newargs = PyTuple_GetSlice(args,0,%d);\n", num_arguments);
      Printf(f->code, "varargs = PyTuple_GetSlice(args,%d,PyTuple_Size(args)+1);\n", num_arguments);
      Printf(f->code, "resultobj = %s__varargs__(self,newargs,varargs);\n", wname);
      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);
    }

    /* Now register the function with the interpreter.   */
    if (!Getattr(n, "sym:overloaded")) {
      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 ((shadow) && (!(shadow & PYSHADOW_MEMBER))) {
	emitFunctionShadowHelper(n, in_class ? f_shadow_stubs : f_shadow, iname, allow_kwargs);
      }
    } else {
      if (!Getattr(n, "sym:nextSibling")) {
	dispatchFunction(n, funpack);
      }
    }
    Delete(parse_args);
    Delete(arglist);
    Delete(get_pointers);
    Delete(cleanup);
    Delete(outarg);
    Delete(kwargs);
    Delete(wname);
    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");

    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 PyDict_SetItemString(d,(char*)\"%s\", SWIG_globals());\n", global_name);
      have_globals = 1;
      if ((shadow) && (!(shadow & PYSHADOW_MEMBER))) {
	Printf(f_shadow_stubs, "%s = %s.%s\n", global_name, module, global_name);
      }
    }
    int assignable = is_assignable(n);

    if ((shadow) && !assignable) {
      if (!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);
      Printf(setf->def, "SWIGINTERN int %s(PyObject *_val) {", varsetname);
      if ((tm = Swig_typemap_lookup("varin", n, name, 0))) {
	Replaceall(tm, "$source", "_val");
	Replaceall(tm, "$target", name);
	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);
    int addfail = 0;
    Printf(getf->def, "SWIGINTERN PyObject *%s(void) {", vargetname);
    Wrapper_add_local(getf, "pyobj", "PyObject *pyobj = 0");
    if ((tm = Swig_typemap_lookup("varout", n, name, 0))) {
      Replaceall(tm, "$source", name);
      Replaceall(tm, "$target", "pyobj");
      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(SWIG_globals(),(char*)\"%s\",%s, %s);\n", iname, vargetname, varsetname);

    Delete(vargetname);
    Delete(varsetname);
    Delete(getname);
    Delete(setname);
    DelWrapper(setf);
    DelWrapper(getf);
    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;
    int have_tm = 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, "$source", value);
      Replaceall(tm, "$target", name);
      Replaceall(tm, "$value", value);
      Printf(const_code, "%s,\n", tm);
      Delete(tm);
      have_tm = 1;
    }
    if ((tm = Swig_typemap_lookup("constcode", n, name, 0))) {
      Replaceall(tm, "$source", value);
      Replaceall(tm, "$target", name);
      Replaceall(tm, "$value", value);
      Printf(f_init, "%s\n", tm);
      Delete(tm);
      have_tm = 1;
    }
    if (!have_tm) {
      Swig_warning(WARN_TYPEMAP_CONST_UNDEF, input_file, line_number, "Unsupported constant value.\n");
      return SWIG_NOWRAP;
    }
    if ((shadow) && (!(shadow & PYSHADOW_MEMBER))) {
      if (!in_class) {
	Printv(f_shadow, iname, " = ", module, ".", iname, "\n", NIL);
      } else {
	if (!(Getattr(n, "feature:python:callback"))) {
	  Printv(f_shadow_stubs, iname, " = ", module, ".", iname, "\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 (shadow) {
      Printv(f_shadow_stubs, name, " = ", module, ".", name, "\n", NIL);
    }
    return SWIG_OK;
  }



/* ----------------------------------------------------------------------------
 * BEGIN C++ Director Class modifications
 * ------------------------------------------------------------------------- */

/* C++/Python polymorphism demo code, copyright (C) 2002 Mark Rose <mrose@stm.lbl.gov>
 *
 * 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, 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, 0, 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\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* protected_method_name) const {\n");
      Printf(f_directors_h, "      std::map<std::string, bool>::const_iterator iv = swig_inner.find(protected_method_name);\n");
      Printf(f_directors_h, "      return (iv != swig_inner.end() ? iv->second : false);\n");
      Printf(f_directors_h, "    }\n\n");

      Printf(f_directors_h, "    void swig_set_inner(const char* protected_method_name, bool val) const\n");
      Printf(f_directors_h, "    { swig_inner[protected_method_name] = val;}\n\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\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) {
      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);
#ifdef USE_THISOWN
      Printv(f_shadow, tab8, "self.thisown = 0\n", NIL);
#else
      Printv(f_shadow, tab8, "self.this.disown()\n", NIL);
#endif
      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 *importname = NewString("");
	String *modname = Getattr(mod, "name");
	if (Strcmp(modname, mainmodule) != 0) {
	  // check if the module has a package option
	  Node *options = Getattr(mod, "options");
	  String *pkg = options ? Getattr(options, "package") : 0;
	  if (pkg && (!package || Strcmp(pkg, package) != 0)) {
	    Printf(importname, "%s.", pkg);
	  }
	  Printf(importname, "%s.", modname);
	}
	Append(importname, Getattr(n, "sym:name"));
	Setattr(n, "python:proxy", importname);
      }
    }
    return Language::classDeclaration(n);
  }

  /* ------------------------------------------------------------
   * classHandler()
   * ------------------------------------------------------------ */

  virtual int classHandler(Node *n) {
    int oldclassic = classic;
    int oldmodern = modern;
    File *f_shadow_file = f_shadow;

    if (shadow) {

      /* Create new strings for building up a wrapper function */
      have_constructor = 0;
      have_repr = 0;

      if (GetFlag(n, "feature:classic")) {
	classic = 1;
	modern = 0;
      }
      if (GetFlag(n, "feature:modern")) {
	classic = 0;
	modern = 1;
      }
      if (GetFlag(n, "feature:exceptionclass")) {
	classic = 1;
	modern = 0;
      }

      shadow_indent = (String *) tab4;

      class_name = Getattr(n, "sym:name");
      real_classname = Getattr(n, "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 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) {
	    Putc(',', base_class);
	  }
	}
      }

      /* dealing with abstract base class */
      String *abcs = Getattr(n, "feature:python:abc");
      if (py3 && abcs) {
        if (Len(base_class)) {
          Putc(',', base_class);
        }
        Printv(base_class, abcs, NIL);
      }
      
      Printv(f_shadow, "class ", class_name, NIL);

      if (Len(base_class)) {
	Printf(f_shadow, "(%s)", base_class);
      } else {
	if (!classic) {
	  Printf(f_shadow, modern ? "(object)" : "(_object)");
	}
        if (GetFlag(n, "feature:exceptionclass") ) {
          Printf(f_shadow, "(Exception)");
        }
      }
      Printf(f_shadow, ":\n");
      if (have_docstring(n)) {
	String *str = docstring(n, AUTODOC_CLASS, tab4);
	if (str && Len(str))
	  Printv(f_shadow, tab4, str, "\n", NIL);
      }
      if (!modern) {
	Printv(f_shadow, tab4, "__swig_setmethods__ = {}\n", NIL);
	if (Len(base_class)) {
	  Printf(f_shadow, "%sfor _s in [%s]: __swig_setmethods__.update(getattr(_s,'__swig_setmethods__',{}))\n", tab4, base_class);
	}

	if (!GetFlag(n, "feature:python:nondynamic")) {
	  Printv(f_shadow, tab4, "__setattr__ = lambda self, name, value: _swig_setattr(self, ", class_name, ", name, value)\n", NIL);
	} else {
	  Printv(f_shadow, tab4, "__setattr__ = lambda self, name, value: _swig_setattr_nondynamic(self, ", class_name, ", name, value)\n", NIL);
	}

	Printv(f_shadow, tab4, "__swig_getmethods__ = {}\n", NIL);
	if (Len(base_class)) {
	  Printf(f_shadow, "%sfor _s in [%s]: __swig_getmethods__.update(getattr(_s,'__swig_getmethods__',{}))\n", tab4, base_class);
	}

	Printv(f_shadow, tab4, "__getattr__ = lambda self, name: _swig_getattr(self, ", class_name, ", name)\n", NIL);
      } else {
	Printv(f_shadow, tab4, "thisown = _swig_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_method(object.__setattr__)\n",
		 tab4, "class __metaclass__(type):\n", tab4, tab4, "__setattr__ = _swig_setattr_nondynamic_method(type.__setattr__)\n", NIL);
	}
      }
    }

    /* Emit all of the members */

    in_class = 1;

    /* Overide the shadow file so we can capture its methods */
    f_shadow = NewString("");

    Language::classHandler(n);
    in_class = 0;

    /* Complete the class */
    if (shadow) {
      /* Generate a class registration function */
      {
        String *smartptr = Getattr(n, "feature:smartptr"); // Replace storing a pointer to underlying class with a smart pointer (intended for use with non-intrusive smart pointers)
        SwigType *smart = 0;
        if (smartptr) {
          SwigType *cpt = Swig_cparse_type(smartptr);
          if (cpt) {
            smart = SwigType_typedef_resolve_all(cpt);
            Delete(cpt);
          } else {
            // TODO: report line number of where the feature comes from
            Swig_error(Getfile(n), Getline(n), "Invalid type (%s) in 'smartptr' feature for class %s.\n", smartptr, real_classname);
          }
        }
	SwigType *ct = Copy(smart ? smart : real_classname);
        SwigType_add_pointer(ct);
	SwigType *realct = Copy(real_classname);
        SwigType_add_pointer(realct);
	SwigType_remember(realct);
	Printv(f_wrappers, "SWIGINTERN PyObject *", class_name, "_swigregister(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {\n", NIL);
	Printv(f_wrappers, "  PyObject *obj;\n", NIL);
	if (modernargs) {
	  if (fastunpack) {
	    Printv(f_wrappers, "  if (!SWIG_Python_UnpackTuple(args,(char*)\"swigregister\", 1, 1,&obj)) return NULL;\n", NIL);
	  } else {
	    Printv(f_wrappers, "  if (!PyArg_UnpackTuple(args,(char*)\"swigregister\", 1, 1,&obj)) return NULL;\n", NIL);
	  }
	} else {
	  Printv(f_wrappers, "  if (!PyArg_ParseTuple(args,(char*)\"O:swigregister\", &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);
	Delete(smart);
	Delete(cname);
	Delete(ct);
	Delete(realct);
      }
      if (!have_constructor) {
	Printv(f_shadow_file, tab4, "def __init__(self, *args, **kwargs): raise AttributeError(\"", "No constructor defined", (Getattr(n, "abstract") ? " - class is abstract" : ""), "\")\n", NIL);
      } else if (fastinit) {

	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) {
	/* Supply a repr method for this class  */
	String *rname = SwigType_namestr(real_classname);
	if (new_repr) {
	  Printv(f_shadow_file, tab4, "__repr__ = _swig_repr\n", NIL);
	} else {
	  Printv(f_shadow_file, tab4, "def __repr__(self):\n", tab8, "return \"<C ", rname, " instance at 0x%x>\" % (self.this,)\n", NIL);
	}
	Delete(rname);
      }


      /* Now emit methods */
      Printv(f_shadow_file, f_shadow, NIL);

      /* Now the Ptr class */
      if (classptr) {
	Printv(f_shadow_file, "\nclass ", class_name, "Ptr(", class_name, "):\n", tab4, "def __init__(self, this):\n", NIL);
	if (!modern) {
	  Printv(f_shadow_file,
		 tab8, "try: self.this.append(this)\n",
		 tab8, "except: self.this = this\n", tab8, "self.this.own(0)\n", tab8, "self.__class__ = ", class_name, "\n\n", NIL);
	} else {
	  Printv(f_shadow_file,
		 tab8, "try: self.this.append(this)\n",
		 tab8, "except: self.this = this\n", tab8, "self.this.own(0)\n", tab8, "self.__class__ = ", class_name, "\n\n", NIL);
	}
      }

      if (fastproxy) {
	List *shadow_list = Getattr(n, "shadow_methods");
	for (int i = 0; i < Len(shadow_list); ++i) {
	  String *symname = Getitem(shadow_list, i);
	  Printf(f_shadow_file, "%s.%s = new_instancemethod(%s.%s,None,%s)\n", class_name, symname, module, Swig_name_member(NSPACE_TODO, class_name, symname), class_name);
	}
      }
      Printf(f_shadow_file, "%s_swigregister = %s.%s_swigregister\n", class_name, module, class_name);
      Printf(f_shadow_file, "%s_swigregister(%s)\n", class_name, class_name);

      shadow_indent = 0;
      Printf(f_shadow_file, "%s\n", f_shadow_stubs);
      Clear(f_shadow_stubs);
    }
    classic = oldclassic;
    modern = oldmodern;

    /* 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;

    /* 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 (!Getattr(n, "sym:nextSibling")) {
      if (shadow) {
	int allow_kwargs = (check_kwargs(n) && !Getattr(n, "sym:overloaded")) ? 1 : 0;
	int fproxy = fastproxy;
	if (Strcmp(symname, "__repr__") == 0) {
	  have_repr = 1;
	}
	if (Getattr(n, "feature:shadow")) {
	  String *pycode = pythoncode(Getattr(n, "feature:shadow"), tab4);
	  String *pyaction = NewStringf("%s.%s", module, Swig_name_member(NSPACE_TODO, class_name, symname));
	  Replaceall(pycode, "$action", pyaction);
	  Delete(pyaction);
	  Printv(f_shadow, pycode, "\n", NIL);
	  Delete(pycode);
	  fproxy = 0;
	} else {
          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, tab4, "def ", symname, "(", parms, ")", returnTypeAnnotation(n), ":", NIL);
	      Printv(f_shadow, " return ", funcCall(Swig_name_member(NSPACE_TODO, class_name, symname), callParms), "\n", NIL);
	    }
	  } else {
	    Printv(f_shadow, tab4, "def ", symname, "(",parms , ")", returnTypeAnnotation(n), ":", NIL);
	    Printv(f_shadow, "\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, pythoncode(pythonprepend(n), tab8), "\n", NIL);
	    }
	    if (have_pythonappend(n)) {
	      fproxy = 0;
	      Printv(f_shadow, tab8, "val = ", funcCall(Swig_name_member(NSPACE_TODO, class_name, symname), callParms), "\n", NIL);
	      Printv(f_shadow, pythoncode(pythonappend(n), tab8), "\n", NIL);
	      Printv(f_shadow, tab8, "return val\n\n", NIL);
	    } else {
	      Printv(f_shadow, tab8, "return ", funcCall(Swig_name_member(NSPACE_TODO, class_name, symname), callParms), "\n\n", NIL);
	    }
	  }
	}
	if (fproxy) {
	  List *shadow_list = Getattr(getCurrentClass(), "shadow_methods");
	  if (!shadow_list) {
	    shadow_list = NewList();
	    Setattr(getCurrentClass(), "shadow_methods", shadow_list);
	    Delete(shadow_list);
	  }
	  Append(shadow_list, symname);
	}
      }
    }
    return SWIG_OK;
  }

  /* ------------------------------------------------------------
   * staticmemberfunctionHandler()
   * ------------------------------------------------------------ */

  virtual int staticmemberfunctionHandler(Node *n) {
    String *symname = Getattr(n, "sym:name");
    Language::staticmemberfunctionHandler(n);

    if (Getattr(n, "sym:nextSibling")) {
      return SWIG_OK;
    }

    if (shadow) {
      if (!classic && !Getattr(n, "feature:python:callback") && have_addtofunc(n)) {
	int kw = (check_kwargs(n) && !Getattr(n, "sym:overloaded")) ? 1 : 0;
        String *parms = make_pyParmList(n, false, false, kw);
        String *callParms = make_pyParmList(n, false, true, kw);
	Printv(f_shadow, 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, pythoncode(pythonprepend(n), tab8), "\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, pythoncode(pythonappend(n), tab8), "\n", NIL);
	  Printv(f_shadow, tab8, "return val\n\n", NIL);
	} else {
	  Printv(f_shadow, tab8, "return ", funcCall(Swig_name_member(NSPACE_TODO, class_name, symname), callParms), "\n\n", NIL);
	}
	Printv(f_shadow, tab4, modern ? "" : "if _newclass:", symname, " = staticmethod(", symname, ")\n", NIL);

	if (!modern) {
	  Printv(f_shadow, tab4, "__swig_getmethods__[\"", symname, "\"] = lambda x: ", symname, "\n", NIL);
	}

      } else {
	if (!modern) {
	  Printv(f_shadow, tab4, "__swig_getmethods__[\"", symname, "\"] = lambda x: ", module, ".", Swig_name_member(NSPACE_TODO, class_name, symname), "\n", NIL);
	}
	if (!classic) {
	  Printv(f_shadow, tab4, modern ? "" : "if _newclass:", symname, " = staticmethod(", module, ".", Swig_name_member(NSPACE_TODO, class_name, symname), ")\n", NIL);
	}
      }
    }
    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);
	}
        
          if (!have_constructor && handled_as_init) {
	  if (Getattr(n, "feature:shadow")) {
	    String *pycode = pythoncode(Getattr(n, "feature:shadow"), tab4);
	    String *pyaction = NewStringf("%s.%s", module, Swig_name_construct(NSPACE_TODO, symname));
	    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);
            

            String *parms = make_pyParmList(n, true, false, allow_kwargs);
            /* Pass 'self' only if using director */
            String *callParms = make_pyParmList(n, false, true, allow_kwargs);

            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, 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, pythoncode(pythonprepend(n), tab8), "\n", NIL);
	    Printv(f_shadow, pass_self, NIL);
	    if (fastinit) {
	      Printv(f_shadow, tab8, module, ".", class_name, "_swiginit(self,", funcCall(Swig_name_construct(NSPACE_TODO, symname), callParms), ")\n", NIL);
	    } else {
	      Printv(f_shadow,
		     tab8, "this = ", funcCall(Swig_name_construct(NSPACE_TODO, symname), callParms), "\n",
		     tab8, "try: self.this.append(this)\n", tab8, "except: self.this = this\n", NIL);
	    }
	    if (have_pythonappend(n))
	      Printv(f_shadow, pythoncode(pythonappend(n), tab8), "\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 (Getattr(n, "feature:shadow")) {
	    String *pycode = pythoncode(Getattr(n, "feature:shadow"), "");
	    String *pyaction = NewStringf("%s.%s", module, Swig_name_construct(NSPACE_TODO, symname));
	    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, pythoncode(pythonprepend(n), tab4), "\n", NIL);
	    Printv(f_shadow_stubs, tab4, "val = ", funcCall(Swig_name_construct(NSPACE_TODO, symname), callParms), "\n", NIL);
#ifdef USE_THISOWN
	    Printv(f_shadow_stubs, tab4, "val.thisown = 1\n", NIL);
#endif
	    if (have_pythonappend(n))
	      Printv(f_shadow_stubs, pythoncode(pythonappend(n), tab4), "\n", NIL);
	    Printv(f_shadow_stubs, tab4, "return val\n", NIL);
	  }
	}
      }
    }
    return SWIG_OK;
  }

  /* ------------------------------------------------------------
   * destructorHandler()
   * ------------------------------------------------------------ */

  virtual int destructorHandler(Node *n) {
    String *symname = Getattr(n, "sym:name");
    int oldshadow = shadow;

    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 = pythoncode(Getattr(n, "feature:shadow"), tab4);
	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)) {
	  if (proxydel) {
	    Printv(f_shadow, tab4, "__del__ = lambda self : None;\n", NIL);
	  }
	  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, pythoncode(pythonprepend(n), tab8), "\n", NIL);
#ifdef USE_THISOWN
	Printv(f_shadow, tab8, "try:\n", NIL);
	Printv(f_shadow, tab8, tab4, "if self.thisown: ", module, ".", Swig_name_destroy(NSPACE_TODO, symname), "(self)\n", NIL);
	Printv(f_shadow, tab8, "except: pass\n", NIL);
#else
#endif
	if (have_pythonappend(n))
	  Printv(f_shadow, pythoncode(pythonappend(n), tab8), "\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) {
      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);
      if (shadow) {
	int assignable = is_assignable(n);
	if (!modern) {
	  if (assignable) {
	    Printv(f_shadow, tab4, "__swig_setmethods__[\"", symname, "\"] = ", module, ".", setname, "\n", NIL);
	  }
	  Printv(f_shadow, tab4, "__swig_getmethods__[\"", symname, "\"] = ", module, ".", getname, "\n", NIL);
	}
	if (!classic) {
	  if (!assignable) {
	    Printv(f_shadow, tab4, modern ? "" : "if _newclass:", symname, " = _swig_property(", module, ".", getname, ")\n", NIL);
	  } else {
	    Printv(f_shadow, tab4, modern ? "" : "if _newclass:", symname, " = _swig_property(", module, ".", getname, ", ", module, ".", setname, ")\n", NIL);
	  }
	}
      }
      Delete(mname);
      Delete(setname);
      Delete(getname);
    }

    return SWIG_OK;
  }

  /* ------------------------------------------------------------
   * staticmembervariableHandler()
   * ------------------------------------------------------------ */

  virtual int staticmembervariableHandler(Node *n) {
    Language::staticmembervariableHandler(n);

    if (shadow && !GetFlag(n, "wrappedasconstant")) {
      String *symname = Getattr(n, "sym:name");
      if (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) {
	  Wrapper *f = NewWrapper();
	  Printv(f->def, "SWIGINTERN PyObject *", wrapsetname, "(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {", NIL);
	  Wrapper_add_local(f, "value", "PyObject *value");
	  Wrapper_add_local(f, "res", "int res");
	  Append(f->code, "if (!PyArg_ParseTuple(args,(char *)\"O:set\",&value)) return NULL;\n");
	  Printv(f->code, "res = ", varsetname, "(value);\n", NIL);
	  Append(f->code, "return !res ? SWIG_Py_Void() : NULL;\n");
	  Append(f->code, "}\n");
	  Wrapper_print(f, f_wrappers);
	  add_method(setname, wrapsetname, 0);
	  DelWrapper(f);
	}
	if (!modern) {
	  if (assignable) {
	    Printv(f_shadow, tab4, "__swig_setmethods__[\"", symname, "\"] = ", module, ".", setname, "\n", NIL);
	  }
	  Printv(f_shadow, tab4, "__swig_getmethods__[\"", symname, "\"] = ", module, ".", getname, "\n", NIL);
	}
	if (!classic) {
	  if (!assignable) {
	    Printv(f_shadow, tab4, modern ? "" : "if _newclass:", symname, " = _swig_property(", module, ".", getname, ")\n", NIL);
	  } else {
	    Printv(f_shadow, tab4, modern ? "" : "if _newclass:", symname, " = _swig_property(", module, ".", getname, ", ", module, ".", setname, ")\n", NIL);
	  }
	}
	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");
    int oldshadow = shadow;
    if (shadow)
      shadow = shadow | PYSHADOW_MEMBER;
    Language::memberconstantHandler(n);
    shadow = oldshadow;

    if (shadow) {
      Printv(f_shadow, tab4, symname, " = ", module, ".", Swig_name_member(NSPACE_TODO, class_name, symname), "\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 = pythoncode(code, shadow_indent);
	Printv(f_shadow, 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");
  }

};

/* ---------------------------------------------------------------
 * 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;
  String *type;
  String *name;
  String *classname;
  String *c_classname = Getattr(parent, "name");
  String *declaration;
  ParmList *l;
  Wrapper *w;
  String *tm;
  String *wrap_args = NewString("");
  String *return_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;
    }
  }

  classname = Getattr(parent, "sym:name");
  type = Getattr(n, "type");
  name = Getattr(n, "name");

  w = NewWrapper();
  declaration = NewString("");

  /* determine if the method returns a pointer */
  decl = Getattr(n, "decl");
  is_pointer = SwigType_ispointer_return(decl);
  is_void = (!Cmp(type, "void") && !is_pointer);

  /* form complete return type */
  return_type = Copy(type);
  {
    SwigType *t = Copy(decl);
    SwigType *f = 0;
    f = SwigType_pop_function(t);
    SwigType_push(return_type, t);
    Delete(f);
    Delete(t);
  }

  /* virtual method definition */
  l = Getattr(n, "parms");
  String *target;
  String *pclassname = NewStringf("SwigDirector_%s", classname);
  String *qualified_name = NewStringf("%s::%s", pclassname, name);
  SwigType *rtype = Getattr(n, "conversion_operator") ? 0 : type;
  target = Swig_method_decl(rtype, decl, qualified_name, l, 0, 0);
  Printf(w->def, "%s", target);
  Delete(qualified_name);
  Delete(target);
  /* header declaration */
  target = Swig_method_decl(rtype, decl, name, l, 0, 1);
  Printf(declaration, "    virtual %s", target);
  Delete(target);

  // Get any exception classes in the throws typemap
  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 ((tm = 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) {
    if (!(ignored_method && !pure_virtual)) {
      String *cres = SwigType_lstr(return_type, "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++ -> Python) */
    String *arglist = NewString("");
    String *parse_args = NewString("");

    /* remove the wrapper 'w' since it was producing spurious temps */
    Swig_typemap_attach_parms("in", l, 0);
    Swig_typemap_attach_parms("directorin", l, 0);
    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);
	  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);
	  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_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, "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_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);
	  }
	  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 || !modernargs) {
	Printf(w->code, "swig::SwigVar_PyObject result = PyObject_CallFunction(method, (char *)\"(%s)\" %s);\n", parse_args, arglist);
      } else {
	Printf(w->code, "swig::SwigVar_PyObject result = PyObject_CallFunctionObjArgs(method %s, NULL);\n", arglist);
      }
    } else {
      if (modernargs) {
	Append(w->code, "swig::SwigVar_PyObject args = PyTuple_New(0);\n");
	Append(w->code, "swig::SwigVar_PyObject result = PyObject_Call(method, (PyObject*) args, NULL);\n");
      } else {
	Printf(w->code, "swig::SwigVar_PyObject result = PyObject_CallFunction(method, NULL, NULL);\n");
      }
    }
    Append(w->code, "#else\n");
    if (Len(parse_args) > 0) {
      if (use_parse || !modernargs) {
	Printf(w->code, "swig::SwigVar_PyObject result = PyObject_CallMethod(swig_get_self(), (char *)\"%s\", (char *)\"(%s)\" %s);\n",
	       pyname, parse_args, arglist);
      } else {        
	Printf(w->code, "swig::SwigVar_PyObject swig_method_name = SWIG_Python_str_FromChar((char *)\"%s\");\n", pyname);
	Printf(w->code, "swig::SwigVar_PyObject result = PyObject_CallMethodObjArgs(swig_get_self(), (PyObject *) swig_method_name %s, NULL);\n", arglist);
      }
    } else {
      if (!modernargs) {
	Printf(w->code, "swig::SwigVar_PyObject result = PyObject_CallMethod(swig_get_self(), (char *) \"%s\", NULL);\n", pyname);
      } else {
	Printf(w->code, "swig::SwigVar_PyObject swig_method_name = SWIG_Python_str_FromChar((char *)\"%s\");\n", pyname);
	Append(w->code, "swig::SwigVar_PyObject result = PyObject_CallMethodObjArgs(swig_get_self(), (PyObject *) swig_method_name, NULL);\n");
      }
    }
    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, "result", 0);
    if (!tm) {
      tm = Getattr(n, "feature:director:except");
      if (tm)
	tm = Copy(tm);
    }
    Append(w->code, "if (!result) {\n");
    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 aruments, 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");
      Append(w->code, "if (!PyTuple_Check(result)) {\n");
      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) {
      /* this seems really silly.  the node's type excludes
       * qualifier/pointer/reference markers, which have to be retrieved
       * from the decl field to construct return_type.  but the typemap
       * lookup routine uses the node's type, so we have to swap in and
       * out the correct type.  it's not just me, similar silliness also
       * occurs in Language::cDeclaration().
       */
      Setattr(n, "type", return_type);
      tm = Swig_typemap_lookup("directorout", n, "result", w);
      Setattr(n, "type", type);
      if (tm != 0) {
	if (outputs > 1) {
	  Printf(w->code, "output = PyTuple_GetItem(result, %d);\n", idx++);
	  Replaceall(tm, "$input", "output");
	} else {
	  Replaceall(tm, "$input", "result");
	}
	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(return_type, 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(result, %d);\n", idx++);
	  Replaceall(tm, "$input", "output");
	} else {
	  Replaceall(tm, "$input", "result");
	}
	Replaceall(tm, "$result", Getattr(p, "name"));
	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(return_type, 0);
      if (!SwigType_isreference(return_type)) {
	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")) {
      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(return_type);
  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();
}
