/* -----------------------------------------------------------------------------
 * 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/CableSwig/CableSwig/SWIG/Source/Modules1.1/python.cxx,v 1.3 2003/07/25 16:47:17 hoffman Exp $";

#include "swigmod.h"

#ifndef MACSWIG
#include "swigconfig.h"
#endif

#include <ctype.h>

#define PYSHADOW_MEMBER  0x2

static  String       *const_code = 0;
static  String       *shadow_methods = 0;
static  String       *module = 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_header = 0;
static  File         *f_wrappers = 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;

/* C++ Support + Shadow Classes */

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

static const char *usage = (char *)"\
Python Options (available with -python)\n\
     -ldflags        - Print runtime libraries to link with\n\
     -globals name   - Set name used to access C global variable ('cvar' by default).\n\
     -interface name - Set the lib name\n\
     -keyword        - Use keyword arguments\n\
     -classic        - Use classic classes only\n\
     -noexcept       - No automatic exception handling.\n\
     -noproxy        - Don't generate proxy classes. \n\n";

class PYTHON : public Language {
public:

  /* ------------------------------------------------------------
   * 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],"-noproxy") == 0)) {
	  shadow = 0;
	  Swig_mark_arg(i);
	} else if (strcmp(argv[i],"-keyword") == 0) {
	  use_kw = 1;
	  Swig_mark_arg(i);
	} else if (strcmp(argv[i],"-classic") == 0) {
	  classic = 1;
	  Swig_mark_arg(i);
	} else if (strcmp(argv[i],"-help") == 0) {
	  fputs(usage,stderr);
	} else if (strcmp (argv[i], "-ldflags") == 0) {
	  printf("%s\n", SWIG_PYTHON_RUNTIME);
	  SWIG_exit (EXIT_SUCCESS);
	}
      }
    }
    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) {

    /* Initialize all of the output files */
    String *outfile = Getattr(n,"outfile");

    f_runtime = NewFile(outfile,"w");
    if (!f_runtime) {
      Printf(stderr,"*** Can't open '%s'\n", outfile);
      SWIG_exit(EXIT_FAILURE);
    }
    f_init = NewString("");
    f_header = NewString("");
    f_wrappers = NewString("");

    /* Register file targets with the SWIG file handler */
    Swig_register_filebyname("header",f_header);
    Swig_register_filebyname("wrapper",f_wrappers);
    Swig_register_filebyname("runtime",f_runtime);
    Swig_register_filebyname("init",f_init);

    const_code     = NewString("");
    shadow_methods = NewString("");
    methods        = NewString("");

    Swig_banner(f_runtime);

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

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

    char  filen[256];

    /* If shadow classing is enabled, we're going to change the module name to "_module" */
    if (shadow) {
      sprintf(filen,"%s%s.py", Swig_file_dirname(outfile), 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);
      }
      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",
	     "# This file is compatible with both classic and new-style classes.\n",
	     NIL);

      Printf(f_shadow,"import %s\n", module);

      // Python-2.2 object hack


      Printv(f_shadow,
	     "def _swig_setattr(self,class_type,name,value):\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",
	     //	   tab8, "if (name == \"this\") or (name == \"thisown\"): self.__dict__[name] = value; return\n",
	     tab4, "method = class_type.__swig_setmethods__.get(name,None)\n",
	     tab4, "if method: return method(self,value)\n",
	     tab4, "self.__dict__[name] = value\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",
	       "\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(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, 0 }\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}};\n");
    Printf(f_wrappers,"%s\n",const_code);
    Printf(f_init,"}\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);
    Dump(f_wrappers,f_runtime);
    Wrapper_pretty_print(f_init,f_runtime);
    Delete(f_header);
    Delete(f_wrappers);
    Delete(f_init);
    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 %s\n", modname);
      }
    }
    return Language::importDirective(n);
  }

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

  void add_method(String *name, String *function, int kw) {
    if (!kw)
      Printf(methods,"\t { (char *)\"%s\", %s, METH_VARARGS, 0 },\n", name, function);
    else
      Printf(methods,"\t { (char *)\"%s\", (PyCFunction) %s, METH_VARARGS | METH_KEYWORDS, 0 },\n", name, function);
  }
  
  /* ------------------------------------------------------------
   * 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");

    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 = (use_kw || Getattr(n,"feature:kwargs")) ? 1 : 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");

  /* 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) {
	Printv(f->def,
	       "static PyObject *", wname,
	       "(PyObject *self, PyObject *args) {\n(void)self; (void)args;",
	       NIL);
      } else {
	Printv(f->def,
	       "static PyObject *", wname, "__varargs__", 
	       "(PyObject *self, PyObject *args, PyObject *varargs) {\n(void)self; (void)args; (void)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;
      }
      Printv(f->def,
	     "static PyObject *", wname,
	     "(PyObject *self, PyObject *args, PyObject *kwargs) {\n(void)self; (void)args; (void)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,"\"%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);
      }
    }
      
    /* Emit the function call */
    emit_action(n,f);

    /* 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");
      }
      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) {\n(void)self; (void)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);

      /* Create a shadow for this function (if enabled and not in a member function) */
      if ((shadow) && (!(shadow & PYSHADOW_MEMBER))) {
	if (in_class) {
	  Printv(f_shadow_stubs,iname, " = ", module, ".", iname, "\n\n", NIL);
	} else {
	  Printv(f_shadow,iname, " = ", module, ".", iname, "\n\n", NIL);	  
	}
      }
    } 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;
  }

  /* ------------------------------------------------------------
   * 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) {\n(void)self;",
	   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);
    Printf(f->code,"PyErr_SetString(PyExc_TypeError,\"No matching function for overloaded '%s'\");\n", symname);
    Printf(f->code,"return NULL;\n");
    Printv(f->code,"}\n",NIL);
    Wrapper_print(f,f_wrappers);
    add_method(symname,wname,0);

    /* Create a shadow for this function (if enabled and not in a member function) */
    if ((shadow) && (!(shadow & PYSHADOW_MEMBER))) {
      Printv(f_shadow_stubs,symname, " = ", module, ".", symname, "\n\n", NIL);
    }
    DelWrapper(f);
    Delete(dispatch);
    Delete(tmp);
    Delete(wname);
  }

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

    if ((shadow) && (SwigType_isconst(t))) {
	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 */

    Printf(setf->def,"static int %s_set(PyObject *_val) {", wname);
    if (!Getattr(n,"feature:immutable")) {
      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 */
      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() {", wname);
    Wrapper_add_local(getf,"pyobj", "PyObject *pyobj");
    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 link with 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   *value = 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);
      Printf(f_header, "static %s = %s;\n", SwigType_str(type,wname), value);
      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 {
	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;
  }

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

  virtual int classDeclaration(Node *n) {
    String *importname;
    Node   *mod;
    if (shadow) {
      mod = Getattr(n,"module");
      if (mod) {
	String *modname = Getattr(mod,"name");
	if (Strcmp(modname,mainmodule) != 0) {
	  importname = NewStringf("%s.%s", modname, Getattr(n,"sym:name"));
	} else {
	  importname = NewString(Getattr(n,"sym:name"));
	}
	Setattr(n,"python:proxy",importname);
      }
    }
    return Language::classDeclaration(n);
  }

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

  virtual int classHandler(Node *n) {
    int oldclassic = classic;

    if (shadow) {

      /* Create new strings for building up a wrapper function */
      have_constructor = 0;
      have_repr = 0;
      
      if (Getattr(n,"cplus:exceptionclass")) {
	classic = 1;
      }
      if (Getattr(n,"feature:classic")) classic = 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)) {
	Node *base = Firstitem(baselist);
	while (base) {
	  String *bname = Getattr(base, "python:proxy");
	  if (!bname) {
	    base = Nextitem(baselist);
	    continue;
	  }
	  Printv(base_class,bname,NIL);
	  base = Nextitem(baselist);
	  if (base) {
	    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,"(_object)");
	}
      }
      Printf(f_shadow,":\n");

      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);
      }
      
      Printv(f_shadow,
	     tab4, "__setattr__ = lambda self, name, value: _swig_setattr(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);
    }

    /* Emit all of the members */

    in_class = 1;
    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);
	Printv(f_wrappers,
	       "static PyObject * ", class_name, "_swigregister(PyObject *self, PyObject *args) {\n(void)self; (void)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,tab4,"def __init__(self): raise RuntimeError, \"No constructor defined\"\n",NIL);
      }

      if (!have_repr) {
	/* Supply a repr method for this class  */
	Printv(f_shadow,
	       tab4, "def __repr__(self):\n",
	       tab8, "return \"<C ", class_name," instance at %s>\" % (self.this,)\n",
	       NIL);
      }
      /* Now build the real class with a normal constructor */
      Printv(f_shadow,
	     "\nclass ", class_name, "Ptr(", class_name, "):\n",
	     tab4, "def __init__(self,this):\n",
	     tab8, "self.this = this\n",
	     tab8, "if not hasattr(self,\"thisown\"): self.thisown = 0\n",
	     //	   tab8,"try: self.this = this.this; self.thisown = getattr(this,'thisown',0); this.thisown=0\n",
	     //	   tab8,"except AttributeError: self.this = this\n"
	     tab8, "self.__class__ = ", class_name, "\n",
	     NIL);

      Printf(f_shadow,"%s.%s_swigregister(%sPtr)\n", module, class_name, class_name,0);
      shadow_indent = 0;
      Printf(f_shadow,"%s\n", f_shadow_stubs);
      Clear(f_shadow_stubs);
    }
    classic = oldclassic;
    return SWIG_OK;
  }

  /* ------------------------------------------------------------
   * 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 = (use_kw || Getattr(n,"feature:kwargs")) ? 1 : 0;
	if (Strcmp(symname,"__repr__") == 0)
	  have_repr = 1;
	
	if (Getattr(n,"feature:shadow")) {
	  String *pycode = pythoncode(Getattr(n,"feature:shadow"),tab4);
	  Printv(f_shadow,pycode,"\n",NIL);
	} else {
	  if (allow_kwargs && !Getattr(n,"sym:overloaded")) {
	    Printv(f_shadow,tab4, "def ", symname, "(*args, **kwargs): ", NIL);
	    Printv(f_shadow, "return apply(", module, ".", Swig_name_member(class_name,symname), ",args, kwargs)\n", NIL);
	  } else {
	    Printv(f_shadow, tab4, "def ", symname, "(*args): ", NIL);
	    Printv(f_shadow, "return apply(", module, ".", Swig_name_member(class_name,symname), ",args)\n",NIL);
	  }
	}
      }
    }
    return SWIG_OK;
  }

  /* ------------------------------------------------------------
   * staticmemberfunctionHandler()
   * ------------------------------------------------------------ */
  
  virtual int staticmemberfunctionHandler(Node *n) {
    String *symname = Getattr(n,"sym:name");
    Language::staticmemberfunctionHandler(n);
    if (shadow) {
      Printv(f_shadow, tab4, "__swig_getmethods__[\"", symname, "\"] = lambda x: ", module, ".", Swig_name_member(class_name, symname), "\n",  NIL);
      if (!classic) {
	Printv(f_shadow, tab4, "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;

    if (shadow) shadow = shadow | PYSHADOW_MEMBER;
    Language::constructorHandler(n);
    shadow = oldshadow;

    if (!Getattr(n,"sym:nextSibling")) {
      if (shadow) {
	int allow_kwargs = (use_kw || Getattr(n,"feature:kwargs")) ? 1 : 0;
	if (!have_constructor) {
	  if (Getattr(n,"feature:shadow")) {
	    String *pycode = pythoncode(Getattr(n,"feature:shadow"),tab4);
	    Printv(f_shadow,pycode,"\n",NIL);
	  } else {
	    if ((allow_kwargs) && (!Getattr(n,"sym:overloaded"))) {
	      Printv(f_shadow, tab4, "def __init__(self,*args,**kwargs):\n", NIL);
	      Printv(f_shadow, tab8, "self.this = apply(", module, ".", Swig_name_construct(symname), ",args,kwargs)\n", NIL);
	    }  else {
	      Printv(f_shadow, tab4, "def __init__(self,*args):\n",NIL);
	      Printv(f_shadow, tab8, "self.this = apply(", module, ".", Swig_name_construct(symname), ",args)\n", NIL);
	    }
	    Printv(f_shadow,
		   tab8, "self.thisown = 1\n",
		   NIL);
	  }
	  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"),"");
	    Printv(f_shadow_stubs,pycode,"\n",NIL);
	  } else {
	    if ((allow_kwargs) && (!Getattr(n,"sym:overloaded"))) 
	      Printv(f_shadow_stubs, "def ", symname, "(*args,**kwargs):\n", NIL);
	    else
	      Printv(f_shadow_stubs, "def ", symname, "(*args):\n", NIL);
	    
	    Printv(f_shadow_stubs, tab4, "val = apply(", NIL);
	    if ((allow_kwargs) && (!Getattr(n,"sym:overloaded"))) 
	      Printv(f_shadow_stubs, module, ".", Swig_name_construct(symname), ",args,kwargs)\n", NIL);
	    else
	      Printv(f_shadow_stubs, module, ".", Swig_name_construct(symname), ",args)\n", NIL);
	    Printv(f_shadow_stubs,tab4, "val.thisown = 1\n",
		   tab4, "return val\n\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) {
      Printv(f_shadow, tab4, "def __del__(self, destroy= ", module, ".", Swig_name_destroy(symname), "):\n", NIL);
      Printv(f_shadow, tab8, "try:\n", NIL);
      Printv(f_shadow, tab4, tab8, "if self.thisown: destroy(self)\n", NIL);
      Printv(f_shadow, tab8, "except: pass\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 immutable = 0;
      if (!Getattr(n,"feature:immutable")) {
	Printv(f_shadow, tab4, "__swig_setmethods__[\"", symname, "\"] = ", module, ".", Swig_name_set(Swig_name_member(class_name,symname)), "\n", NIL);
      } else {
	immutable = 1;
      }
      Printv(f_shadow, tab4, "__swig_getmethods__[\"", symname, "\"] = ", module, ".", Swig_name_get(Swig_name_member(class_name,symname)),"\n", NIL);

      if (!classic) {
	if (immutable) {
	  Printv(f_shadow,tab4,"if _newclass:", symname," = property(", module, ".", 
		 Swig_name_get(Swig_name_member(class_name,symname)),")\n", NIL);
	} else {
	  Printv(f_shadow,tab4,"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;
  }

  /* ------------------------------------------------------------
   * 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 = DohSplit(temp,'\n',-1);
    Delete(temp);
    int   initial = 0;
    String *s;

  /* Get the initial indentation */
    for (s = Firstitem(clist); s; s = Nextitem(clist)) {
      if (Len(s)) {
	char *c = Char(s);
	while (*c) {
	  if (!isspace(*c)) break;
	  initial++;
	  c++;
	}
	if (*c && !isspace(*c)) break;
	else {
	  initial = 0;
	}
      }
    }
    while (s) {
      if (Len(s) > initial) {
	char *c = Char(s);
	c += initial;
	Printv(out,indent,c,"\n",NIL);
      } else {
	Printv(out,"\n",NIL);
      }
      s = Nextitem(clist);
    }
    Delete(clist);
    return out;
  }

  /* ------------------------------------------------------------
   * 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, "\n", NIL);
	Delete(pycode);
      }
    } else {
      Language::insertDirective(n);
    }
    return SWIG_OK;
  }
};

/* -----------------------------------------------------------------------------
 * swig_python()    - Instantiate module
 * ----------------------------------------------------------------------------- */

extern "C" Language *
swig_python(void) {
  return new PYTHON();
}
