/* -----------------------------------------------------------------------------
 * python.cxx
 *
 *     Python module.
 *
 * Author(s) : David Beazley (beazley@cs.uchicago.edu)
 *
 * Copyright (C) 1999-2000.  The University of Chicago
 * See the file LICENSE for information on usage and redistribution.
 * ----------------------------------------------------------------------------- */

char cvsroot_python_cxx[] = "$Header: /cvsroot/swig/SWIG/Source/Modules/python.cxx,v 1.94 2005/06/03 21:25:00 wsfulton Exp $";

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

#include <ctype.h>

#define PYSHADOW_MEMBER  0x2

static  String       *const_code = 0;
static  String       *shadow_methods = 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  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 = 0;
static  File         *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           apply = 0;
static  int           new_repr = 1;
static int            no_header_file = 0;

/* C++ Support + Shadow Classes */

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

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

static const char *usage = (char *)"\
Python Options (available with -python)\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\
     -classic        - Use classic classes only\n\
     -cppcast        - Enable new C++ casting operators, useful for debugging\n\
     -nortti         - Disable the use of the native C++ RTTI with directors\n\
     -modern         - Use modern python features only, without compatibility code\n\
     -apply          - Use apply() in proxy classes\n\
     -new_vwm        - New value wrapper mode, use only when everything else fails \n\
     -new_repr       - Use more informative version of __repr__ in proxy classes\n\
     -old_repr       - Use shorter and old version of __repr__ in proxy classes\n\
     -noexcept       - No automatic exception handling\n\
     -noh            - Don't generate the output header file\n\
     -noproxy        - Don't generate proxy classes \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",
	   "  PyErr_SetString(PyExc_RuntimeError,",
	   "    \"accessing abstract class or protected constructor\"); \n",
	   "  SWIG_fail;\n",
	   "}\n", NIL);
    director_multiple_inheritance = 1;
    director_language = 1;
  }
  
  /* ------------------------------------------------------------
   * main()
   * ------------------------------------------------------------ */
  
  virtual void main(int argc, char *argv[]) {

    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],"-apply") == 0) {
          apply = 1;
          Swig_mark_arg(i);
        } else if (strcmp(argv[i],"-new_repr") == 0) {
          new_repr = 1;
          Swig_mark_arg(i);
        } else if (strcmp(argv[i],"-old_repr") == 0) {
          new_repr = 0;
          Swig_mark_arg(i);
	} else if ((strcmp(argv[i],"-noproxy") == 0)) {
	  shadow = 0;
	  Swig_mark_arg(i);
	} else if (strcmp(argv[i],"-keyword") == 0) {
	  use_kw = 1;
          SWIG_cparse_set_compact_default_args(1);
	  Swig_mark_arg(i);
	} else if (strcmp(argv[i],"-classic") == 0) {
	  classic = 1;
	  apply = 1;
	  Swig_mark_arg(i);
	} else if (strcmp(argv[i],"-cppcast") == 0) {
	  /* Turn on new value wrapper mpde */
	  Preprocessor_define((DOH *) "SWIG_CPLUSPLUS_CAST", 0);
	  Swig_mark_arg(i);
	} else if (strcmp(argv[i],"-nortti") == 0) {
	  /* Turn on no RTTI mode */
	  Preprocessor_define((DOH *) "SWIG_NORTTI", 0);
	  Swig_mark_arg(i);
	} else if (strcmp(argv[i],"-modern") == 0) {
	  apply = 0;
	  classic = 0;
          modern = 1;
	  Swig_mark_arg(i);
	} else if (strcmp(argv[i],"-noh") == 0) {
	  no_header_file = 1;
	  Swig_mark_arg(i);
	} else if (strcmp(argv[i],"-new_vwm") == 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],"-help") == 0) {
	  fputs(usage,stdout);
	}
      }
    }
    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();
          }
          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_runtime = NewFile(outfile,"w");
    if (!f_runtime) {
      Printf(stderr,"*** Can't open '%s'\n", outfile);
      SWIG_exit(EXIT_FAILURE);
    }
    
    if (directorsEnabled()) {
      if (!no_header_file) {
	f_runtime_h = NewFile(outfile_h,"w");
	if (!f_runtime_h) {
	  Printf(stderr,"*** Can't open '%s'\n", outfile_h);
	  SWIG_exit(EXIT_FAILURE);
	}
      } else {
	f_runtime_h = f_runtime;
      }
    }

    f_init = NewString("");
    f_header = NewString("");
    f_wrappers = NewString("");
    f_directors_h = NewString("");
    f_directors = NewString("");

    /* Register file targets with the SWIG file handler */
    Swig_register_filebyname("header",f_header);
    Swig_register_filebyname("wrapper",f_wrappers);
    Swig_register_filebyname("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("");
    shadow_methods = NewString("");
    methods        = NewString("");

    Swig_banner(f_runtime);

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

    if (directorsEnabled()) {
      Printf(f_runtime,"#define SWIG_DIRECTORS\n");
    }

    /* Set module name */
    module = Copy(Getattr(n,"name"));
    mainmodule = Getattr(n,"name");

    if (directorsEnabled()) {
      Swig_banner(f_directors_h);
      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_h, "class Swig::Director;\n\n"); */
      Swig_insert_file("director_h.swg", f_directors_h);
      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));
      }
      Swig_insert_file("director.swg", f_directors);
    }

    /* 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 = NewFile(filen,"w")) == 0) {
	Printf(stderr,"Unable to open %s\n", filen);
	SWIG_exit (EXIT_FAILURE);
      }
      Delete(filen); filen = NULL;

      f_shadow_stubs = NewString("");

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

      Printv(f_shadow,
	     "# This file was created automatically by SWIG.\n",
	     "# Don't modify this file, modify the SWIG interface instead.\n",
	     NIL);

      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;
      }
      
      Printf(f_shadow,"\nimport %s\n\n", module);

      /* 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 == \"this\"):\n",
               tab4, tab4, "if isinstance(value, class_type):\n",
               tab4, tab8, "self.__dict__[name] = value.this\n",
               tab4, tab8, "if hasattr(value,\"thisown\"): self.__dict__[\"thisown\"] = value.thisown\n",
               tab4, tab8, "del value.thisown\n",
               tab4, tab8, "return\n",
               tab4, "method = class_type.__swig_setmethods__.get(name,None)\n",
               tab4, "if method: return method(self,value)\n",
	       tab4, "if (not static) or hasattr(self,name) or (name == \"thisown\"):\n",
               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, "method = class_type.__swig_getmethods__.get(name,None)\n",
               tab4, "if method: return method(self)\n",
               tab4, "raise AttributeError,name\n\n",
               NIL);

        if (!classic) {
          Printv(f_shadow,
                 "import types\n",
                 "try:\n",
                 "    _object = types.ObjectType\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",
	       tab4, tab4, "if hasattr(self,name) or (name in (\"this\", \"thisown\")):\n",
	       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, "from weakref import proxy as 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,"#define SWIG_init    init%s\n\n", module);
    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");
    Printf(const_code,"static swig_const_info swig_const_table[] = {\n");
    Printf(methods,"static PyMethodDef SwigMethods[] = {\n");

    /* emit code */
    Language::top(n);

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

    SwigType_emit_type_table(f_runtime,f_wrappers);

    Printf(const_code, "{0, 0, 0, 0.0, 0, 0}};\n");
    Printf(f_wrappers,"%s\n",const_code);
    Printf(f_init,"}\n");

    Printf(f_wrappers,"#ifdef __cplusplus\n");
    Printf(f_wrappers,"}\n");
    Printf(f_wrappers,"#endif\n");

    if (shadow) {
      Printv(f_shadow, f_shadow_stubs, "\n",NIL);
      Close(f_shadow);
      Delete(f_shadow);
    }

    /* Close all of the files */
    Dump(f_header,f_runtime);

    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_runtime) Close(f_runtime_h);
      Dump(f_directors, f_runtime);
    }

    Dump(f_wrappers,f_runtime);
    Wrapper_pretty_print(f_init,f_runtime);

    Delete(f_header);
    Delete(f_wrappers);
    Delete(f_init);
    Delete(f_directors);
    Delete(f_directors_h);

    Close(f_runtime);

    return SWIG_OK;
  }

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

  virtual int importDirective(Node *n) {
    if (shadow) {
      String *modname = Getattr(n,"module");
      if (modname) {
        Printf(f_shadow,"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(f_shadow, "%s.", pkg);
        }

        // finally, output the name of the imported module
	Printf(f_shadow, "%s\n", modname);
      }
    }
    return Language::importDirective(n);
  }


  /* ------------------------------------------------------------
   * emitFuncCallHelper()
   *    Write the shadow code to call a function in the extension
   *    module.  Takes into account the -apply flag and whether
   *    to use keyword args or not.
   * ------------------------------------------------------------ */

  String *funcCallHelper(String *name, int kw) {
    String *str;
    
    str = NewString("");
    if (apply) {
      Printv(str, "apply(", module, ".", name, ", args", (kw ? ", kwargs" : ""), ")", NIL);
    } else {
      Printv(str, module, ".", name, "(*args", (kw ? ", **kwargs" : ""), ")", NIL);
    }
    return str;
  }

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

  String *pythoncode(String *code, const String *indent) {
    String *out = NewString("");
    String *temp;
    char   *t;
    if (!indent) indent = "";

    temp = NewString(code);

    t = Char(temp);
    if (*t == '{') {
      Delitem(temp,0);
      Delitem(temp,DOH_END);
    }

    /* Split the input text into lines */
    List *clist = 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 != NULL && Len(str) > 0) ||
        (Getattr(n,"feature:autodoc") && !Getattr(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 != NULL && Len(str) > 0);
    bool have_auto = (Getattr(n,"feature:autodoc") && !Getattr(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 != NULL && 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') == NULL) {
        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') == NULL) {
        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;
  }

  /* ------------------------------------------------------------
   * make_autodocParmList()
   *   Generate the documentation for the function parameters
   * ------------------------------------------------------------ */

  String* make_autodocParmList(Node* n, bool showTypes) {
    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;
    const int maxwidth = 50;

    if (pdocs) Printf(pdocs, "\n");


    Swig_typemap_attach_parms("in",plist,0);
    Swig_typemap_attach_parms("doc",plist,0);
    
    for (p = plist; p; p = pnext) {
      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");

      String* tm = Getattr(p,"tmap:in");
      if (tm) {
	pnext = Getattr(p,"tmap:in:next");
      } else {
	pnext = nextSibling(p);
      }

      if ( Len(doc) ) {
        // add a comma to the previous one if any
        Printf(doc, ", ");

        // Do we need to wrap a long line?
        if ((Len(doc) - lines*maxwidth) > maxwidth) {
          Printf(doc, "\n%s", tab4);
          lines += 1;
        }
      }
        
      // Do the param type too?
      if (showTypes) {
        type =  SwigType_base(type);
	lookup = Swig_symbol_clookup(type, 0);
	if (lookup) type = Getattr(lookup, "sym:name");
        Printf(doc, "%s ", type);
      }

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

      if (value) {
        if (Strcmp(value, "NULL") == 0)
          value = NewString("None");
        else if (Strcmp(value, "true") == 0 || Strcmp(value, "TRUE") == 0)
          value = NewString("True");
	else if (Strcmp(value, "false") == 0 || Strcmp(value, "FALSE") == 0)
          value = NewString("False");        
	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:
        Printf(doc, "%s", 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 {
            SwigType* qt = SwigType_typedef_resolve_all(type);
            if (SwigType_isenum(qt))
              type = NewString("int");
            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 == NULL || Len(str) == 0) {
              if (CPlusPlus) {
                Printf(doc, "Proxy of C++ %s class", class_name);
              } else {
                Printf(doc, "Proxy of C %s struct", class_name);
              }
            }
          }
	  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:
          Printf(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)
        Printf(doc, "\n");
    }
          
    return doc;
  }

  /* ------------------------------------------------------------
   * 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 != NULL && 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 != NULL && 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);
  }
  

  /* ------------------------------------------------------------
   * 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) {
    if (Getattr(n,"feature:python:callback") || ! have_addtofunc(n) ) {
      /* If there is no addtofunc directive then just assign from the extension module */
      Printv(f_dest, "\n", name, " = ", module, ".", name, "\n", NIL);
    } else {
      /* Otherwise make a wrapper function to insert the code into */
      Printv(f_dest, "\ndef ", name, "(*args", (kw ? ", **kwargs" : ""), "):\n", NIL);
      if ( have_docstring(n) )
        Printv(f_dest, tab4, docstring(n, AUTODOC_FUNC, tab4), "\n", NIL);
      if ( have_pythonprepend(n) )
        Printv(f_dest, tab4, pythonprepend(n), "\n", NIL);
      if ( have_pythonappend(n) ) {
        Printv(f_dest, tab4, "val = ", funcCallHelper(name, kw), "\n", NIL);
        Printv(f_dest, tab4, pythonappend(n), "\n", NIL);
        Printv(f_dest, tab4, "return val\n", NIL);
      } else {
        Printv(f_dest, tab4, "return ", funcCallHelper(name, kw), "\n", NIL);
      }        
    }
  }


  /* ------------------------------------------------------------
   * check_kwargs()
   *    check if using kwargs is allowed for this Node
   * ------------------------------------------------------------ */

  int check_kwargs(Node *n) {
    return ((use_kw || Getattr(n,"feature:kwargs")) && !Getattr(n, "feature:nokwargs")) ? 1 : 0;
  }


    
  /* ------------------------------------------------------------
   * add_method()
   * ------------------------------------------------------------ */

  void add_method(String *name, String *function, int kw, Node *n = 0) {
    if (!kw) 
      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 && Getattr(n,"feature:callback")) {
      if (have_docstring(n)) {
        String* ds = docstring(n, AUTODOC_FUNC, "", false);
        Replaceall(ds, "\n", "\\n");
	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 {
      Printf(methods,"NULL");
    }
    

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

  /* ------------------------------------------------------------
   * dispatchFunction()
   * ------------------------------------------------------------ */
  void dispatchFunction(Node *n) {
    /* Last node in overloaded chain */

    int maxargs;
    String *tmp = NewString("");
    String *dispatch = Swig_overload_dispatch(n,"return %s(self,args);",&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,	
	   "static 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);
    Wrapper_add_local(f,"ii","int ii");
    Printf(f->code,"argc = PyObject_Length(args);\n");
    Printf(f->code,"for (ii = 0; (ii < argc) && (ii < %d); ii++) {\n",maxargs);
    Printf(f->code,"argv[ii] = PyTuple_GetItem(args,ii);\n");
    Printf(f->code,"}\n");
    
    Replaceall(dispatch,"$args","self,args");
    Printv(f->code,dispatch,"\n",NIL);
    if (checkAttribute(n,"feature:python:maybecall","1")) {
      Printf(f->code,"Py_INCREF(Py_NotImplemented);\n");
      Printf(f->code,"return Py_NotImplemented;\n");
    } else {
      Printf(f->code,"PyErr_SetString(PyExc_NotImplementedError,\"No matching function for overloaded '%s'\");\n", symname);
      Printf(f->code,"return NULL;\n");
    }
    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()
   * ------------------------------------------------------------ */

  virtual int functionWrapper(Node *n) {
  
    String  *name  = Getattr(n,"name");
    String  *iname = Getattr(n,"sym:name");
    SwigType *d    = Getattr(n,"type");
    ParmList *l    = Getattr(n,"parms");
    Node *parent   = Getattr(n,"parentNode");

    Parm    *p;
    int     i;
    char    wname[256];
    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");
    int isVirtual = (Cmp(storage,"virtual") == 0);

    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("");
    
    Wrapper_add_local(f,"resultobj", "PyObject *resultobj = NULL");

  /* Write code to extract function parameters. */
    emit_args(d, 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);
    varargs = emit_isvarargs(l);

    strcpy(wname,Char(Swig_name_wrapper(iname)));
    if (overname) {
      strcat(wname,Char(overname));
    }

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

    /* Generate code for argument marshalling */

    Printf(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");

      sprintf(source,"obj%d",i);

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

      /* Keyword argument handling */
      if (Len(pn)) {
	Printf(kwargs,"(char *) \"%s\",", pn);
      } else {
	Printf(kwargs,"\"arg%d\",", i+1);
      }

      /* Look for an input typemap */
      if ((tm = Getattr(p,"tmap:in"))) {
	String *parse = Getattr(p,"tmap:in:parse");
	if (!parse) {
	  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");
	  }

	  Putc('O',parse_args);
	  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 {
	  Printf(parse_args,"%s",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;
      }
      p = nextSibling(p);
    }

    /* finish argument marshalling */
    Printf(kwargs," NULL }");
    if (allow_kwargs) {
      Printv(f->locals,tab4, "char *kwnames[] = ", kwargs, ";\n", NIL);
    }

    Printf(parse_args,":%s\"", iname);
    Printv(parse_args,
	   arglist, ")) goto 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 ((tm = Getattr(p,"tmap:freearg"))) {
	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.

    if (directorsEnabled()) {
      if (!is_smart_pointer()) {
        if (/*directorbase &&*/ !constructor && !destructor 
	    && isVirtual  && !Getattr(n,"feature:nodirector")) {
          Wrapper_add_local(f, "director", "Swig::Director *director = 0");
          Printf(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, "PyErr_SetString(PyExc_RuntimeError,\"accessing protected member %s\");\n", name);
	    Printf(f->code, "SWIG_fail;\n");
	    Printf(f->code, "}\n");
	  }
          Printf(f->code, "if (director && (director->swig_get_self()==obj0)) director->swig_set_up();\n");
	}
      }
    }

    /* for constructor, determine if Python class has been subclassed.
     * if so, create a director instance.  otherwise, just create a normal instance.
     */
    /* MOVED TO Swig_ConstructorToFunction() */
    /*
    if (constructor && (Getattr(n, "wrap:self") != 0)) {
      Wrapper_add_local(f, "subclassed", "int subclassed = 0");
      Printf(f->code, "subclassed = (arg1 != Py_None);\n");
    }
    */
     
    /* Emit the function call */
    if (directorsEnabled()) {
      Printf(f->code, "try {\n");
      Printf(f->code, "  Swig::UnknownExceptionHandler dh;\n");
    }
    
    emit_action(n,f);

    if (directorsEnabled()) {
      Printf(f->code, "} catch (Swig::DirectorException&) {\n");
      Printf(f->code, "  SWIG_fail;\n");
      Printf(f->code, "}\n");
    }
    

    /* This part below still needs cleanup */

    /* Return the function value */
    if ((tm = Swig_typemap_lookup_new("out",n,"result",0))) {
      Replaceall(tm,"$source", "result");
      Replaceall(tm,"$target", "resultobj");
      Replaceall(tm,"$result", "resultobj");
      if (Getattr(n,"feature:new")) {
	Replaceall(tm,"$owner","1");
      } 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. 
       */
      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 *module = Getattr(parent, "module");
        Node *target = Swig_directormap(module, type);
	if (target) unwrap = 1;
      }
      if (unwrap) {
      	Wrapper_add_local(f, "resultdirector", "Swig::Director *resultdirector = 0");
	Printf(f->code, "resultdirector = SWIG_DIRECTOR_CAST(result);\n");
	Printf(f->code, "if (resultdirector) {\n");
	Printf(f->code, "  resultobj = resultdirector->swig_get_self();\n");
	Printf(f->code, "  Py_INCREF(resultobj);\n");
	Printf(f->code, "} else {\n"); 
        Printf(f->code,"%s\n", tm);
        Printf(f->code, "}\n");
      } else {
        Printf(f->code,"%s\n", tm);
      }
    } else {
      Swig_warning(WARN_TYPEMAP_OUT_UNDEF, input_file, line_number,
		   "Unable to use return type %s in function %s.\n", SwigType_str(d,0), name);
    }

    /* Output argument output code */
    Printv(f->code,outarg,NIL);

    /* Output cleanup code */
    Printv(f->code,cleanup,NIL);

    /* Look to see if there is any newfree cleanup code */
    if (Getattr(n,"feature:new")) {
      if ((tm = Swig_typemap_lookup_new("newfree",n,"result",0))) {
	Replaceall(tm,"$source","result");
	Printf(f->code,"%s\n",tm);
      }
    }

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

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

    /* Error handling code */

    Printf(f->code,"fail:\n");
    Printv(f->code,cleanup,NIL);
    Printf(f->code,"return NULL;\n");
    Printf(f->code,"}\n");

    /* Substitute the cleanup code */
    Replaceall(f->code,"$cleanup",cleanup);

    /* Substitute the function name */
    Replaceall(f->code,"$symname",iname);
    Replaceall(f->code,"$result","resultobj");

    /* 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,
	     "static 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);
      Printf(f->code,"Py_XDECREF(newargs);\n");
      Printf(f->code,"Py_XDECREF(varargs);\n");
      Printf(f->code,"return resultobj;\n");
      Printf(f->code,"}\n");
      Wrapper_print(f,f_wrappers);
    }

    Setattr(n,"wrap:name", wname);

    /* Now register the function with the interpreter.   */
    if (!Getattr(n,"sym:overloaded")) {
      add_method(iname, wname, allow_kwargs, n);

      /* 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);
      }
    }
    Delete(parse_args);
    Delete(arglist);
    Delete(get_pointers);
    Delete(cleanup);
    Delete(outarg);
    Delete(kwargs);
    DelWrapper(f);
    return SWIG_OK;
  }



  /* ------------------------------------------------------------
   * variableWrapper()
   * ------------------------------------------------------------ */

  virtual int variableWrapper(Node *n) {
    String *name  = Getattr(n,"name");
    String *iname = Getattr(n,"sym:name");
    SwigType *t = Getattr(n,"type");
    
    String *wname;
    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);
      }
    }

    wname = Swig_name_wrapper(iname);

    /* Create a function for setting the value of the variable */

    if (assignable) {
      Printf(setf->def,"static int %s_set(PyObject *_val) {", wname);
      if ((tm = Swig_typemap_lookup_new("varin",n,name,0))) {
	Replaceall(tm,"$source","_val");
	Replaceall(tm,"$target",name);
	Replaceall(tm,"$input","_val");
	Printf(setf->code,"%s\n",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));
      }
      Printf(setf->code,"    return 0;\n");
    } else {
      /* Is a readonly variable.  Issue an error */
      if (CPlusPlus) {
	Printf(setf->def,"static int %s_set(PyObject *) {", wname);
      } else {
	Printf(setf->def,"static int %s_set(PyObject *_val) {", wname);
      }
      Printv(setf->code,
	     tab4, "PyErr_SetString(PyExc_TypeError,\"Variable ", iname,
	     " is read-only.\");\n",
	     tab4, "return 1;\n",
	     NIL);
    }

    Printf(setf->code,"}\n");
    Wrapper_print(setf,f_wrappers);

    /* Create a function for getting the value of a variable */
    Printf(getf->def,"static PyObject *%s_get(void) {", wname);
    Wrapper_add_local(getf,"pyobj", "PyObject *pyobj = NULL");
    if ((tm = Swig_typemap_lookup_new("varout",n,name,0))) {
      Replaceall(tm,"$source",name);
      Replaceall(tm,"$target","pyobj");
      Replaceall(tm,"$result","pyobj");
      Printf(getf->code,"%s\n", tm);
    } else {
      Swig_warning(WARN_TYPEMAP_VAROUT_UNDEF, input_file, line_number,
		   "Unable to read variable of type %s\n", SwigType_str(t,0));
    }
    
    Printf(getf->code,"    return pyobj;\n}\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_get, %s_set);\n", iname, wname, wname);

    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_new("consttab",n,name,0))) {
      Replaceall(tm,"$source",value);
      Replaceall(tm,"$target",name);
      Replaceall(tm,"$value", value);
      Printf(const_code,"%s,\n", tm);
      have_tm = 1;
    }
    if ((tm = Swig_typemap_lookup_new("constcode", n, name, 0))) {
      Replaceall(tm,"$source",value);
      Replaceall(tm,"$target",name);
      Replaceall(tm,"$value",value);
      Printf(f_init, "%s\n", 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\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 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"));
    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(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);
        Printf(w->def, "}\n");
        Delete(target);
        Wrapper_print(w, f_directors);
        Delete(call);
        DelWrapper(w);
      }

      /* constructor header */
      {
        String *target = Swig_method_decl(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);
      Printf(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) {
    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 know, 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* name) const {\n");
      Printf(f_directors_h,"      std::map<std::string, bool>::const_iterator iv = inner.find(name);\n");
      Printf(f_directors_h,"      return (iv != inner.end() ? iv->second : false);\n");
      Printf(f_directors_h,"    }\n\n");
      
      Printf(f_directors_h,"    void swig_set_inner(const char* name, bool val) const\n");
      Printf(f_directors_h,"    { inner[name] = val;}\n\n");
      Printf(f_directors_h,"private:\n");
      Printf(f_directors_h,"    mutable std::map<std::string, bool> inner;\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(symname); //Getattr(n, "name"));
      Printv(f_shadow, tab4, "def __disown__(self):\n", NIL);
      Printv(f_shadow, tab8, "self.thisown = 0\n", NIL);
      Printv(f_shadow, tab8, module, ".", mrename,"(self)\n", NIL);
      Printv(f_shadow, tab8, "return weakref_proxy(self)\n", NIL);
      Delete(mrename);
    }
    return result;
  }

/*************************************************************************************
 * END of C++ Director Class modifications
 ************************************************************************************/
 

  /* ------------------------------------------------------------
   * classDeclaration()
   * ------------------------------------------------------------ */

  virtual int classDeclaration(Node *n) {
    if (shadow && !Getattr(n,"feature:onlychildren")) {
      Node   *mod = Getattr(n,"module");
      if (mod) {
	String *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);
	}
	Printf(importname,"%s", 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 (Getattr(n,"feature:exceptionclass")) {
	classic = 1;
        modern  = 0;
      }
      if (Getattr(n,"feature:classic")) {
        classic = 1;
        modern  = 0;
      }
      if (Getattr(n,"feature:modern")) {
        classic = 0;
        modern = 1;
      }

      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");
	  if (!bname || Getattr(b.item,"feature:ignore")) {
	    b = Next(b);
	    continue;
	  }
	  Printv(base_class,bname,NIL);
	  b = Next(b);
	  if (b.item) {
	    Putc(',',base_class);
	  }
	}
      }
      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)");
	}
      }
      Printf(f_shadow,":\n");
      if ( have_docstring(n) ) {
        String* str = docstring(n, AUTODOC_CLASS, tab4);
        if (str != NULL && 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(_s.__swig_setmethods__)\n",tab4,base_class);
        }

	if (!checkAttribute(n,"feature:python:nondynamic","1")) {
	  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(_s.__swig_getmethods__)\n",tab4,base_class);
        }
      
        Printv(f_shadow,
               tab4, "__getattr__ = lambda self, name: _swig_getattr(self, ", class_name, ", name)\n",
               NIL);
      } else {
	/* Add static attribute */
	if (checkAttribute(n,"feature:python:nondynamic","1")) {
	  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 */
      {
	SwigType  *ct = NewStringf("p.%s", real_classname);
	SwigType_remember(ct);
        if (CPlusPlus) {
	  Printv(f_wrappers,
	         "static PyObject * ", class_name, "_swigregister(PyObject *, PyObject *args) {\n",
	         tab4, "PyObject *obj;\n",
	         tab4, "if (!PyArg_ParseTuple(args,(char*)\"O\", &obj)) return NULL;\n",
  	         tab4, "SWIG_TypeClientData(SWIGTYPE", SwigType_manglestr(ct),", obj);\n",
  	         tab4, "Py_INCREF(obj);\n",
	         tab4, "return Py_BuildValue((char *)\"\");\n",
	         "}\n",NIL);
        } else {
	  Printv(f_wrappers,
	         "static PyObject * ", class_name, "_swigregister(PyObject *self, PyObject *args) {\n",
	         tab4, "PyObject *obj;\n",
	         tab4, "if (!PyArg_ParseTuple(args,(char*)\"O\", &obj)) return NULL;\n",
  	         tab4, "SWIG_TypeClientData(SWIGTYPE", SwigType_manglestr(ct),", obj);\n",
  	         tab4, "Py_INCREF(obj);\n",
	         tab4, "return Py_BuildValue((char *)\"\");\n",
	         "}\n",NIL);
        }
	String *cname = NewStringf("%s_swigregister", class_name);
	add_method(cname, cname, 0);
	Delete(cname);
	Delete(ct);
      }
      if (!have_constructor) {
	Printv(f_shadow_file,tab4,"def __init__(self): raise RuntimeError, \"No constructor defined\"\n",NIL);
      }

      if (!have_repr) {
	/* Supply a repr method for this class  */
	String *rname = SwigType_namestr(real_classname);
	if (new_repr) {
	  Printv(f_shadow_file,
                 tab4, "def __repr__(self):\n",
                 tab8, "return \"<%s.%s; proxy of ", CPlusPlus ? "C++ " : "C ", rname," instance at %s>\" % (self.__class__.__module__, self.__class__.__name__, self.this,)\n",
                 NIL);
	}
	else {
	  Printv(f_shadow_file,
	         tab4, "def __repr__(self):\n",
  	         tab8, "return \"<C ", rname," instance at %s>\" % (self.this,)\n",
	         NIL);
	}
	Delete(rname);
      }


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

      /* Now the Ptr class */
      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, "_swig_setattr(self, ", class_name, ", 'this', this)\n",
               tab8, "if not hasattr(self,\"thisown\"): _swig_setattr(self, ", class_name, ", 'thisown', 0)\n",
               tab8, "_swig_setattr(self, ", class_name, ",self.__class__,", class_name, ")\n",
               NIL);
      } else {
        Printv(f_shadow_file,
               tab8, "self.this = this\n",
               tab8, "if not hasattr(self,\"thisown\"): self.thisown = 0\n",
               tab8, "self.__class__ = ", class_name, "\n", NIL);
  	     //	   tab8,"try: self.this = this.this; self.thisown = getattr(this,'thisown',0); this.thisown=0\n",
  	     //	   tab8,"except AttributeError: self.this = this\n"
      }

      Printf(f_shadow_file,"%s.%s_swigregister(%sPtr)\n", module, class_name, class_name,0);
      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 */
    f_shadow = f_shadow_file;

    return SWIG_OK;
  }

  /* ------------------------------------------------------------
   * functionHandler()  -  Mainly overloaded for callback handling
   * ------------------------------------------------------------ */

  virtual int functionHandler(Node *n) {
    String *pcb = Getattr(n,"feature:python:callback");
    if (pcb && (Strcmp(pcb,"0") == 0)) {
      Setattr(n,"feature:python:callback","");
      pcb = 0;
    }
    if (pcb) {
      if (Strcmp(pcb,"1") == 0) {
	Setattr(n,"feature:callback","%s_cb_ptr");
      } else {
	Setattr(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;
	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(class_name,symname));
	  Replaceall(pycode,"$action", pyaction);
	  Delete(pyaction);
	  Printv(f_shadow,pycode,"\n",NIL);
	} else {
	  Printv(f_shadow, tab4, "def ", symname, "(*args", (allow_kwargs ? ", **kwargs" : ""), "):", NIL);
	  if (!have_addtofunc(n)) {
	    Printv(f_shadow, " return ", funcCallHelper(Swig_name_member(class_name,symname), allow_kwargs), "\n", NIL);
	  } else {
            Printv(f_shadow, "\n", NIL);
            if ( have_docstring(n) )
              Printv(f_shadow, tab8, docstring(n, AUTODOC_METHOD, tab8), "\n", NIL);
            if ( have_pythonprepend(n) )
              Printv(f_shadow, tab8, pythonprepend(n), "\n", NIL);
            if ( have_pythonappend(n) ) {
              Printv(f_shadow, tab8, "val = ", funcCallHelper(Swig_name_member(class_name,symname), allow_kwargs), "\n", NIL);
              Printv(f_shadow, tab8, pythonappend(n), "\n", NIL);
              Printv(f_shadow, tab8, "return val\n\n", NIL);
            } else {
              Printv(f_shadow, tab8, "return ", funcCallHelper(Swig_name_member(class_name,symname), allow_kwargs), "\n\n", NIL);
            }
	  }
	}
      }
    }
    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;
        Printv(f_shadow, tab4, "def ", symname, "(*args", (kw ? ", **kwargs" : ""), "):\n", NIL);
        if ( have_docstring(n) )
          Printv(f_shadow, tab8, docstring(n, AUTODOC_STATICFUNC, tab8), "\n", NIL);
        if ( have_pythonprepend(n) )
          Printv(f_shadow, tab8, pythonprepend(n), "\n", NIL);
        if ( have_pythonappend(n) ) {
          Printv(f_shadow, tab8, "val = ", funcCallHelper(Swig_name_member(class_name, symname), kw), "\n", NIL);
          Printv(f_shadow, tab8, pythonappend(n), "\n", NIL);
          Printv(f_shadow, tab8, "return val\n\n", NIL);
        } else {
          Printv(f_shadow, tab8, "return ", funcCallHelper(Swig_name_member(class_name, symname), kw), "\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(class_name, symname), "\n",  NIL);
        }
        if (!classic) {
	  Printv(f_shadow, tab4, modern ? "" : "if _newclass:",  symname,
		 " = staticmethod(", module, ".",
		 Swig_name_member(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);
	  Delete(type);
	  Delete(name);
	  Setattr(self, "lname", "O");
	  if (parms) set_nextSibling(self, parms);
	  Setattr(n, "parms", self);
	  Setattr(n, "wrap:self", "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;
	if (!have_constructor) {
	  if (Getattr(n,"feature:shadow")) {
	    String *pycode = pythoncode(Getattr(n,"feature:shadow"),tab4);
	    String *pyaction = NewStringf("%s.%s",module, Swig_name_construct(symname));
	    Replaceall(pycode,"$action", pyaction);
	    Delete(pyaction);
	    Printv(f_shadow,pycode,"\n",NIL);
	  } else {
	    String *pass_self = NewString("");
	    Node *parent = Swig_methodclass(n);
	    String *classname = Swig_class_name(parent);
	    String *rclassname = Swig_class_name(getCurrentClass());
	    assert(rclassname);
	    if (use_director) {
 	      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(f_shadow, tab4, "def __init__(self, *args",
                   (allow_kwargs ? ", **kwargs" : ""), "):\n", NIL);
            if ( have_docstring(n) )
              Printv(f_shadow, tab8, docstring(n, AUTODOC_CTOR, tab8), "\n", NIL);
            if ( have_pythonprepend(n) )
              Printv(f_shadow, tab8, pythonprepend(n), "\n", NIL);
            Printv(f_shadow, pass_self, NIL);
            if (!modern) {
              Printv(f_shadow, tab8, "_swig_setattr(self, ", rclassname, ", 'this', ", 
                     funcCallHelper(Swig_name_construct(symname), allow_kwargs), ")\n", NIL);
              Printv(f_shadow, 
                     tab8, "_swig_setattr(self, ", rclassname, ", 'thisown', 1)\n",
                     NIL);
            } else {
              Printv(f_shadow, tab8, "newobj = ",
                     funcCallHelper(Swig_name_construct(symname), allow_kwargs), "\n", NIL);
              Printv(f_shadow, tab8, "self.this = newobj.this\n", NIL);
              Printv(f_shadow, tab8, "self.thisown = 1\n", NIL);
              Printv(f_shadow, tab8, "del newobj.thisown\n", NIL);
            }
            if ( have_pythonappend(n) )
              Printv(f_shadow, tab8, pythonappend(n), "\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(symname));
	    Replaceall(pycode,"$action", pyaction);
	    Delete(pyaction);
	    Printv(f_shadow_stubs,pycode,"\n",NIL);
	  } else {

            Printv(f_shadow_stubs, "\ndef ", symname, "(*args",
                   (allow_kwargs ? ", **kwargs" : ""), "):\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, tab4, pythonprepend(n), "\n", NIL);
            Printv(f_shadow_stubs, tab4, "val = ",
                   funcCallHelper(Swig_name_construct(symname), allow_kwargs), "\n", NIL);
	    Printv(f_shadow_stubs, tab4, "val.thisown = 1\n", NIL);
            if ( have_pythonappend(n) )
              Printv(f_shadow_stubs, tab4, pythonappend(n), "\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;
    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(symname));
	Replaceall(pycode, "$action", pyaction);
	Delete(pyaction);
	Printv(f_shadow,pycode,"\n", NIL);
      } else {
	Printv(f_shadow, tab4, "def __del__(self, destroy=", module, ".", Swig_name_destroy(symname), "):\n", NIL);
        if ( have_docstring(n) )
              Printv(f_shadow, tab8, docstring(n, AUTODOC_DTOR, tab8), "\n", NIL);
	if ( have_pythonprepend(n) )
	  Printv(f_shadow, tab8, pythonprepend(n), "\n", NIL);
	Printv(f_shadow, tab8, "try:\n", NIL);
	Printv(f_shadow, tab8, tab4, "if self.thisown: destroy(self)\n", NIL);
	Printv(f_shadow, tab8, "except: pass\n", NIL);
	if ( have_pythonappend(n) )
	  Printv(f_shadow, tab8, pythonappend(n), "\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) {
      int assignable = is_assignable(n);
      if (!modern) {
        if (assignable) {
          Printv(f_shadow, tab4, "__swig_setmethods__[\"", symname, "\"] = ", module, ".", Swig_name_set(Swig_name_member(class_name,symname)), "\n", NIL);
        } 
        Printv(f_shadow, tab4, "__swig_getmethods__[\"", symname, "\"] = ", module, ".", Swig_name_get(Swig_name_member(class_name,symname)),"\n", NIL);
      }
      if (!classic) {
	if (!assignable) {
	  Printv(f_shadow,tab4, modern ? "" : "if _newclass:",
                 symname," = property(", module, ".", 
		 Swig_name_get(Swig_name_member(class_name,symname)),")\n", NIL);
	} else {
	  Printv(f_shadow,tab4, modern ? "" : "if _newclass:",
                 symname," = property(", 
		 module, ".", Swig_name_get(Swig_name_member(class_name,symname)),", ",
		 module, ".", Swig_name_set(Swig_name_member(class_name,symname)),")\n", NIL);
	}
      }
    }
    return SWIG_OK;
  }

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

  virtual int staticmembervariableHandler(Node *n) {
    String *symname;
    SwigType *t;
    
    Language::staticmembervariableHandler(n);
    if (shadow) {
      t = Getattr(n,"type");
      symname = Getattr(n,"sym:name");
      if (SwigType_isconst(t) && !Getattr(n, "value")) {
	Printf(f_shadow,"%s%s = %s.%s.%s\n", tab4, symname, module, global_name, Swig_name_member(class_name,symname));      
      }
    }
    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(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 = Swig_include_sys("pyrun.swg");
    if (!s) {
      Printf(stderr, "*** Unable to open 'pyrun.swg'\n");
      s = NewString("");
    }
    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::classDirectorMethod(Node *n, Node *parent, String *super) {
  int is_void = 0;
  int is_pointer = 0;
  String *decl;
  String *type;
  String *name;
  String *classname;
  String *declaration;
  ParmList *l;
  Wrapper *w;
  String *tm;
  String *wrap_args;
  String *return_type;
  String *value = Getattr(n, "value");
  String *storage = Getattr(n,"storage");
  bool pure_virtual = false;
  int status = SWIG_OK;
  int idx;
  String* xdecref = NewString("");

  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);
  target = Swig_method_decl(decl, qualified_name, l, 0, 0);
  String *rtype = SwigType_str(type, 0);
  Printf(w->def, "%s %s", rtype, target);
  Delete(qualified_name);
  Delete(target);
  /* header declaration */
  target = Swig_method_decl(decl, name, l, 0, 1);
  Printf(declaration, "    virtual %s %s", rtype, 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);
	Printf(w->def, "%s", str);
	Printf(declaration, "%s", str);
	Delete(str);
      }
    }

    Append(w->def, ")");
    Append(declaration, ")");
  }


  Append(w->def, " {");
  Append(declaration, ";\n");

  /* 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;
  int num_arguments = emit_num_arguments(l);
  int i;
  char source[256];

  wrap_args = NewString("");
  int outputs = 0;
  if (!is_void) outputs++;
	
  /* build argument list and type conversion string */
  for (i=0, idx=0, p = l; i < num_arguments && p != 0; i++) {

    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++);
	Replaceall(tm, "$input", source);
	Replaceall(tm, "$owner", "0");
	Printv(wrap_args, tm, "\n", NIL);
	Wrapper_add_localv(w, source, "PyObject *", source, "= 0", NIL);
	Printv(arglist, source, NIL);
	Putc('O', parse_args);
	Printf(xdecref,"Py_XDECREF(%s);\n", source);
      } else {
	Printf(parse_args, "%s", parse);
	Replaceall(tm, "$input", pname);
	Replaceall(tm, "$owner", "0");
	if (Len(tm) == 0) Append(tm, pname);
	Printf(arglist, "%s", 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), classname, 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, "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);
	    Printf(wrap_args, "} else {\n");
	    Printf(wrap_args,   "%s = %s->swig_get_self();\n", source, director);
	    Printf(wrap_args,   "Py_INCREF(%s);\n", source);
	    Printf(wrap_args, "}\n");
	    Delete(director);
	    Printf(xdecref,"Py_XDECREF(%s);\n", source);
	    Printv(arglist, source, NIL);
	  } else {
	    Wrapper_add_localv(w, source, "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);
	    Printf(xdecref,"Py_XDECREF(%s);\n", source);
	    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), classname, name);
          status = SWIG_NOWRAP;
	  break;
	}
      }
    p = nextSibling(p);
  }

  /* 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) {
    Wrapper_add_localv(w, "c_result", SwigType_lstr(return_type, "c_result"), NIL);
  }
  /* declare Python return value */
  Wrapper_add_local(w, "result", "PyObject *result");

  /* direct call to superclass if _up is set */
  Printf(w->code, "if (swig_get_up()) {\n");
  if (pure_virtual) {
    Printf(w->code,
	   "Swig::DirectorPureVirtualException::raise(\"%s.\");\n",Swig_method_call(super,l));
  } else {
    if (is_void) {
      Printf(w->code, "%s;\n", Swig_method_call(super,l));
      Printf(w->code, "return;\n");
    } else {
      Printf(w->code, "return %s;\n", Swig_method_call(super,l));
    }
  }
  Printf(w->code, "}\n");
    
  /* wrap complex arguments to PyObjects */
  Printv(w->code, wrap_args, NIL);

  String  *pyname = Getattr(n,"sym:name");

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

  Printf(w->code, "if (!swig_get_self()) {\n");
  Printf(w->code, "  Swig::DirectorException::raise(\"'self' unitialized, maybe you forgot to call %s.__init__.\");\n", classname);
  Printf(w->code, "}\n");  
  if (Len(parse_args) > 0) {
    Printf(w->code, "result = PyObject_CallMethod(swig_get_self(), (char *)\"%s\", (char *)\"(%s)\" %s);\n", pyname, parse_args, arglist);
  } else {
    Printf(w->code, "result = PyObject_CallMethod(swig_get_self(), (char *)\"%s\", NULL);\n", pyname);
  }
  Printv(xdecref, "Py_XDECREF(result);\n", NULL);
  if (dirprot_mode() && !is_public(n))
    Printf(w->code, "swig_set_inner(\"%s\", false);\n", name);

  /* exception handling */
  tm = Swig_typemap_lookup_new("director:except", n, "result", 0);
  if (!tm) {
    tm = Getattr(n, "feature:director:except");
  }
  Printf(w->code, "if (result == NULL) {\n");
  Printf(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 {
    Printf(w->code, "  if (error != NULL) {\n");
    Printf(w->code, "    Swig::DirectorMethodException::raise(\"Error detected when calling %s.%s.\\n\");\n", 
	   classname, pyname);
    Printf(w->code, "  }\n");
  }
  
  Printf(w->code, "}\n");

  /*
   * 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");
    Printf(w->code, "if (!PyTuple_Check(result)) {\n");
    Printf(w->code, "  Swig::DirectorTypeMismatchException::raise(\"Python method %s.%sfailed to return a tuple.\");\n",
	   classname, pyname);
    Printf(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_new("directorout", n, "result", w);
    Setattr(n, "type", type);
    if (tm == 0) {
      String *name = NewString("result");
      tm = Swig_typemap_search("directorout", return_type, name, NULL);
      Delete(name);
    }
    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");
      }
      Replaceall(tm, "$result", "c_result");
      Printv(w->code, tm, "\n", NIL);
    } else {
      Swig_warning(WARN_TYPEMAP_DIRECTOROUT_UNDEF, input_file, line_number,
		   "Unable to use return type %s in director method %s::%s (skipping method).\n", SwigType_str(return_type, 0), classname, 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);
    }
  }

  Printv(w->code, xdecref, NULL);
  Delete(xdecref);

  /* any existing helper functions to handle this? */
  if (!is_void) {
    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);
  }

  Printf(w->code, "}\n");

  /* emit the director method */
  if (status == SWIG_OK) {
    if (!Getattr(n,"defaultargs")) {
      Wrapper_print(w, f_directors);
      Printv(f_directors_h, declaration, NIL);
    }
  }

  /* clean up */
  Delete(wrap_args);
  Delete(parse_args);
  Delete(arglist);
  Delete(rtype);
  Delete(return_type);
  Delete(pclassname);
  Delete(cleanup);
  Delete(outarg);
  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();
}

