/*******************************************************************************
 * Simplified Wrapper and Interface Generator  (SWIG)
 * 
 * Author : David Beazley
 *
 * Department of Computer Science        
 * University of Chicago
 * 1100 E 58th Street
 * Chicago, IL  60637
 * beazley@cs.uchicago.edu
 *
 * Please read the file LICENSE for the copyright and terms by which SWIG
 * can be used and distributed.
 *******************************************************************************/

#include "internal.h"

/*******************************************************************************
 * $Header: /cvsroot/SWIG1.1/SWIG/cplus.cxx,v 1.5 1999/11/05 21:45:13 beazley Exp $
 *
 * File : cplus.cxx
 *
 * This module defines parser entry points for supporting C++.  Primarily
 * this module is in charge of keeping track of the contents of C++ classes,
 * organizing inheritance, and other things.
 *
 * Eventually this module will be merged with the type handling mechanism
 * in SWIG 2.0 so it's a little messy right now.
 *
 * General comments :
 *
 * 1.  The words "simple" and "C++" are rarely used in the same
 *     sentence.   Therefore this module is going to be some sort
 *     of compromise.
 *
 * 2.  I'm using the "Annotated C++ Reference Manual" (ARM) as my
 *     reference for handling certain cases.     Of course, there
 *     is a high probability that I have misinterpreted or overlooked
 *     certain cases.
 *
 * 3.  It is not my intent to write a full C++ compiler.
 *
 *     My goals are simple :
 *           -  Support simple ANSI C-like class member functions and data.
 *           -  Support constructors and destructors.
 *           -  static member functions.
 *           -  basic inheritance.
 *           -  virtual functions.
 *           -  References
 *
 *     I do not plan to support the following anytime in the near future 
 *           -  Operator overloading
 *           -  templates
 *
 * Caution :
 *
 * The control flow in this module is completely insane.  But here's the
 * rough outline.
 *
 *       Stage 1 :  SWIG Parsing
 *                  cplus_open_class()        - Open up a new class
 *                  cplus_*                   - Add members to class
 *                  cplus_inherit()           - Inherit from base classes
 *                  cplus_class_close()       - Close class
 *
 *                  ...
 *                  cplus_open_class()
 *                  ... 
 *                  cplus_class_close()
 *
 *                  ... and so on, until the end of the file
 *
 *       After stage 1, all classes have been read, but nothing has been
 *       sent to the language module yet.
 *
 *       Stage 2 :  Code generation
 *                  For each class we've saved, do this :
 *                       lang->cpp_open_class()     - Open class
 *                       lang->cpp_*                - Emit members
 *                       lang->cpp_inherit()        - Inherit
 *                       lang->cpp_close_class()    - Close class
 *
 * This two-stage approach solves a number of problems related to working
 * with multiple files, mutually referenced classes, add adding methods.
 * Just keep in mind that all C++ code is emitted *after* an entire SWIG
 * file has been parsed.
 *
 * Improved code generation and inheritance of added methods (2/18/97):
 *
 * Each C++ declaration now has an associated function name attached to it.
 * For example :
 *
 *            class Foo {
 *                  void bar();
 *            }
 *
 * Generates a member function "bar()" with a accessor function named 
 * "Foo_bar()".  We will use this recorded accessor function to generate
 * better code for inheritance. For example :
 *
 *           class Foo2 : public Foo {
 *
 *               ...
 *           }
 *
 * Will create a function called "Foo2_bar()" that is really mapped
 * onto the base-class method "Foo_bar()".   This should improve
 * code generation substantially.
 *
 * Tricky stuff :
 *        -    Each target language is responsible for naming wrapper
 *             functions.
 *
 *******************************************************************************/

// Some status variables

static int    Inherit_mode = 0;             // Set if we're inheriting members
static char   *ccode = 0;                   // Set to optional C code (if available)
static Hash   *localtypes;                  // Localtype hash
static int    abstract =0;                  // Status bit set during code generation

static int    cpp_id = 0;

// Forward references

void cplus_member_func(char *, char *, DataType *, ParmList *, int);
void cplus_constructor(char *, char *, ParmList *);
void cplus_destructor(char *, char *);
void cplus_variable(char *, char *, DataType *);
void cplus_static_func(char *, char *, DataType *, ParmList *);
void cplus_declare_const(char *, char *, DataType *, char *);
void cplus_static_var(char *, char *, DataType *);
void cplus_inherit_decl(char **);

// -----------------------------------------------------------------------------
// void add_local_type(char *type, char *classname) 
// void add_local_type(DataType *type, char *classname)
// 
// Adds a new datatype to the local datatype hash.   This is used to handle
// datatypes defined within a class.
//
// Inputs : Datatype to place in hash
//
// Output : None
//
// Side Effects : Updates localtypes hash.
// -----------------------------------------------------------------------------

static void add_local_type(char *type, char *classname) {
  String str;
  
  if (!localtypes) return;        // No hash table initialized, ignore this

  str << classname << "::" << type;
  localtypes->add(type,copy_string(str));
}

void add_local_type(DataType *type, char *classname) {
  add_local_type(type->name,classname);
}

// -----------------------------------------------------------------------------
// void update_local_type(DataType *type)
// 
// Checks to see whether this datatype is part of a class definition. If so,
// we update the type-name by appending the class prefix to it.  Uses the
// name stored in current_class unless unavailable.
//
// Inputs : type = Datatype
//
// Output : type is updated with a new name.
//
// Side Effects : None
// -----------------------------------------------------------------------------

static void update_local_type(DataType *type) {
  
  char *newname = 0;

  // Lookup the datatype in the hash table

  if (!localtypes) return;

  newname = (char *) localtypes->lookup(type->name);
  if (newname) {
    strcpy(type->name, newname);
  }
}

// -----------------------------------------------------------------------------
// void update_parms(ParmList *l)
//
// Updates all of the parameters in a parameter list with the proper C++ prefix
// (if neccessary).  
//
// Inputs : l = Parameter list
//
// Output : Parameter list l is updated (make sure its a copy!)
//
// Side Effects : None
// -----------------------------------------------------------------------------

static void update_parms(ParmList *l) {
  Parm *p;
  p = l->get_first();
  while (p) {
    update_local_type(p->t);

    // Check for default arguments

    if ((p->defvalue) && (localtypes)) {
      char *s;
      s = (char *) localtypes->lookup(p->defvalue);
      if (s) {
	delete p->defvalue;
	p->defvalue = copy_string(s);
      }
    }
    p = l->get_next();
  }
}

// -----------------------------------------------------------------------
// class CPP_member
//
// Base class for various kinds of C++ members
// -----------------------------------------------------------------------
class CPP_member {
public:
  char          *name;                   // Name of the member
  char          *iname;                  // Name of member in the interpreter
  int            is_static;              // Is this a static member?
  int            new_method;             // Is this a new method (added by SWIG)?
  int            line;                   // What line number was this member on
  char           *file;                  // What file was this in?
  char           *code;                  // Was there any supplied code?
  char           *base;                  // Base class where this was defined
  int            inherited;              // Was this member inherited?
  DocEntry       *de;                    // Documentation entry
  CPP_member     *next;                  // Next member (for building linked lists)
  int            id;                     // type id when created

  virtual void   inherit(int) { };       // Inheritance rule (optional)
  virtual void   emit() = 0;             // Emit rule
};

// ----------------------------------------------------------------------
// class CPP_function : public CPP_member
//
// Structure for handling a C++ member function
// ----------------------------------------------------------------------

class CPP_function : public CPP_member {
public:
  DataType    *ret_type;  
  ParmList    *parms;
  int          new_object;
  int          is_virtual;

  CPP_function(char *n, char *i, DataType *t, ParmList *l, int s, int v = 0) {
    name = copy_string(n);
    iname = copy_string(i);
    ret_type = new DataType(t);
    parms = new ParmList(l);
    is_static = s;
    is_virtual = v;
    new_method = AddMethods;
    new_object = NewObject;
    inherited = Inherit_mode;
    de = 0;
    next = 0;
    line = line_number;
    file = input_file;
    if (Inherit_mode) {
      id = cpp_id;
    } else {
      id = type_id;
    }
    if (AddMethods) {
      if (strlen(CCode.get()))
	code = copy_string(CCode.get());
      else
	code = 0;
    } else {
      code = 0;
    }
  }
  void inherit(int mode) {
    doc_entry = 0;            // No documentation for an inherited member
    if (mode & INHERIT_FUNC) {
      // Set up the proper addmethods mode and provide C code (if provided)
      int oldaddmethods = AddMethods;
      int oldnewobject = NewObject;
      AddMethods = new_method;
      NewObject = new_object;
      CCode = code;
      if (is_static) {
	cplus_static_func(name, iname, ret_type, parms);
      } else {
	cplus_member_func(name, iname, ret_type, parms, is_virtual);
      }
      AddMethods = oldaddmethods;
      NewObject = oldnewobject;
      CCode = "";
    }
  }
  void emit() {
    ParmList *l;
    DataType *t;
    AddMethods = new_method;
    NewObject = new_object;
    doc_entry = de;            // Restore documentation entry
    line_number = line;        // Restore line and file 
    input_file = file;
    ccode = code;

    // Make a copy of the parameter list and upgrade its types

    l = new ParmList(parms);
    t = new DataType(ret_type);
    update_parms(l);
    update_local_type(t);
    if (is_static) {
      lang->cpp_static_func(name, iname, t, l);
    } else {
      lang->cpp_member_func(name, iname, t, l);
    }
    l->check_defined();
    t->check_defined();
    delete l;
    delete t;
  }
};

// --------------------------------------------------------------------------
// class CPP_constructor : public CPP_member
//
// Class for holding a C++ constructor definition.
// --------------------------------------------------------------------------

class CPP_constructor : public CPP_member {
public:
  ParmList  *parms;
  CPP_constructor(char *n, char *i, ParmList *l) {
    name = copy_string(n);
    iname = copy_string(i);
    parms = new ParmList(l);
    new_method = AddMethods;
    inherited = 0;
    de = 0;
    next = 0;
    line = line_number;
    file = input_file;
    id = type_id;
    if (AddMethods) {
      if (strlen(CCode.get()))
	code = copy_string(CCode.get());
      else
	code = 0;
    } else {
      code = 0;
    }
  }
  void emit() {
    if (1) {
      ParmList *l;
      AddMethods = new_method;
      doc_entry = de;
      line_number = line;
      input_file = file;
      ccode = code;
      
      // Make a copy of the parameter list and upgrade its types
      
      l = new ParmList(parms);
      update_parms(l);
      lang->cpp_constructor(name,iname,l);
      l->check_defined();
      delete l;
    } else {
      if (Verbose) {
	fprintf(stderr,"%s:%d:  Constructor for abstract base class ignored.\n",
		file,line);
      }
    }
  }
};


// --------------------------------------------------------------------------
// class CPP_destructor : public CPP_member
//
// Class for holding a destructor definition
// --------------------------------------------------------------------------

class CPP_destructor : public CPP_member {
public:

  CPP_destructor(char *n, char *i) {
    name = copy_string(n);
    iname = copy_string(i);
    new_method = AddMethods;
    de = 0;
    next = 0;
    inherited = 0;
    line = line_number;
    file = input_file;
    id = type_id;
    if (AddMethods) {
      if (strlen(CCode.get()))
	code = copy_string(CCode.get());
      else
	code = 0;
    } else {
      code = 0;
    }

  }
  void emit() {
    AddMethods = new_method;
    doc_entry = de;
    line_number = line;
    input_file = file;
    ccode = code;
    lang->cpp_destructor(name, iname);
  }
};

// -------------------------------------------------------------------------
// class CPP_variable : public CPP_member
//
// Class for a managing a data member
// -------------------------------------------------------------------------

class CPP_variable : public CPP_member {
public:
  DataType *type;
  int status;
  CPP_variable(char *n, char *i, DataType *t, int s) {
    name = copy_string(n);
    iname = copy_string(i);
    type = new DataType(t);
    is_static = s;
    status = Status;
    de = 0;
    next = 0;
    new_method = AddMethods;
    line = line_number;
    file = input_file;
    if (Inherit_mode) {
      id = cpp_id;
    } else {
      id = type_id;
    }
    code = 0;
    inherited = 0;
  }

  // Emit code for this

  void emit() {
    DataType *t;
    int old_status = Status;
    doc_entry = de;
    AddMethods = new_method;
    Status = status;
    line_number = line;
    input_file = file;
    ccode = code;

    t = new DataType(type);
    if (t->qualifier) {
      //      if (strcmp(t->qualifier,"const") == 0) Status = Status | STAT_READONLY;
    }
    update_local_type(t);
    if (!is_static) {
      lang->cpp_variable(name,iname,t);
    } else {
      lang->cpp_static_var(name,iname,t);
    }
    t->check_defined();
    Status = old_status;
    delete t;
  }

  // Inherit into another class

  void inherit(int mode) {
    int oldstatus = Status;
    Status = status;
    doc_entry = 0;
    if (mode & INHERIT_VAR) {
      if (!is_static) {
	int oldaddmethods = AddMethods;
	AddMethods = new_method;
	CCode = code;
	cplus_variable(name,iname,type);
	AddMethods = oldaddmethods;
	CCode = "";
      } else {
	cplus_static_var(name,iname,type);
      }
    }
    Status = oldstatus;
  }
};

// -------------------------------------------------------------------------
// class CPP_constant : public CPP_member
//
// Class for managing constant values
// -------------------------------------------------------------------------

class CPP_constant : public CPP_member {
public:
  char       *value;
  DataType   *type;
  CPP_constant(char *n, char *i, DataType *t, char *v) {
    name = copy_string(n);
    iname = copy_string(i);
    type = new DataType(t);
    value = copy_string(v);
    de = 0;
    new_method = AddMethods;
    next = 0;
    line = line_number;
    file = input_file;
    if (Inherit_mode)
      id = cpp_id;
    else
      id = type_id;
    code = 0;
    inherited = 0;
  }

  void emit() {
    doc_entry = de;
    AddMethods = new_method;
    line_number = line;
    input_file = file;
    ccode = code;
    lang->cpp_declare_const(name,iname,type,value);
    type->check_defined();
  }

  void inherit(int mode) {
    doc_entry = 0;
    if (mode & INHERIT_CONST) 
      cplus_declare_const(name, iname, type, value);
  }
};

// ----------------------------------------------------------------------
// class CPP_class
//
// Class for managing class members (internally)
// ----------------------------------------------------------------------

static char   *inherit_base_class = 0;

class CPP_class {
public:
  char        *classname;             // Real class name
  char        *classrename;           // New name of class (if applicable)
  char        *classtype;             // class type (struct, union, class)
  int          strip;                 // Strip off class declarator
  int          wextern;               // Value of extern wrapper variable for this class
  int          have_constructor;      // Status bit indicating if we've seen a constructor
  int          have_destructor;       // Status bit indicating if a destructor has been seen
  int          is_abstract;           // Status bit indicating if this is an abstract class
  int          generate_default;      // Generate default constructors
  int          objective_c;           // Set if this is an objective C class
  int          error;                 // Set if this class can't be generated
  int          line;                  // Line number
  char        **baseclass;            // Base classes (if any)
  Hash        *local;                 // Hash table for local types
  Hash        *scope;                 // Local scope hash table
  DocEntry    *de;                    // Documentation entry of class
  CPP_member  *members;               // Linked list of members
  CPP_class   *next;                  // Next class
  static CPP_class *classlist;        // List of all classes stored
  Pragma      *pragmas;               // Class pragmas

  CPP_class(char *name, char *ctype) {
    CPP_class *c;
    classname = copy_string(name);
    classtype = copy_string(ctype);
    classrename = 0;
    baseclass = 0;
    de = doc_entry;
    local = new Hash;                 // Create hash table for storing local datatypes
    scope = 0;
    error = 0;
    pragmas = 0;
    line = line_number;

    // Walk down class list and add to end

    c = classlist;
    if (c) {
      while (c->next) {
	c = c->next;
      }
      c->next = this;
    } else {
      classlist = this;
    }
    next = 0;
    members = 0;
    strip = 0;
    wextern = WrapExtern;
    have_constructor = 0;
    have_destructor = 0;
    is_abstract = 0;
    generate_default = GenerateDefault;
    objective_c = ObjCClass;
  }

  // ------------------------------------------------------------------------------
  // Add a new C++ member to this class
  // ------------------------------------------------------------------------------

  void add_member(CPP_member *m) {
    CPP_member *cm;
    
    // Set base class where this was defined
    if (inherit_base_class)          
      m->base = inherit_base_class;
    else
      m->base = classname;              
    if (!members) {
      members = m;
      return;
    }
    cm = members;
    while (cm->next) {
      cm = cm->next;
    }
    cm->next = m;
  }
  // ------------------------------------------------------------------------------
  // Search for a member with the given name. Returns the member on success, 0 on failure
  // ------------------------------------------------------------------------------

  CPP_member *search_member(char *name) {
    CPP_member *m;
    char *c;
    m = members;
    while (m) {
      c = m->iname ? m->iname : m->name;
      if (strcmp(c,name) == 0) return m;
      m = m->next;
    }
    return 0;
  }

  // ------------------------------------------------------------------------------
  // Inherit.  Put all the declarations associated with this class into the current
  // ------------------------------------------------------------------------------

  void inherit_decls(int mode) {
    CPP_member *m;
    m = members;
    while (m) {
      inherit_base_class = m->base;
      cpp_id = m->id;
      m->inherit(mode);
      m = m->next;
    }
    inherit_base_class = 0;
  }

  // ------------------------------------------------------------------------------
  // Emit all of the declarations associated with this class 
  // ------------------------------------------------------------------------------

  void emit_decls() {
    CPP_member    *m = members;
    int  last_scope = name_scope(0);
    abstract = is_abstract;
    while (m) {
      cpp_id = m->id;
      name_scope(cpp_id);         // Set proper naming scope
      m->emit();
      m = m->next;
    }
    name_scope(last_scope);
  }

  // ------------------------------------------------------------------------------  
  // Search for a given class in the list
  // ------------------------------------------------------------------------------

  static CPP_class *search(char *name) {
    CPP_class *c;
    c = classlist;
    if (!name) return 0;
    while (c) {
      if (strcmp(name,c->classname) == 0) return c;
      c = c->next;
    }
    return 0;
  }

  // ------------------------------------------------------------------------------
  // Add default constructors and destructors
  //
  // ------------------------------------------------------------------------------

  void create_default() {
    if (!generate_default) return;
    
    // Try to generate a constructor if not available.
    CCode = "";
    AddMethods = 0;
    if ((!have_constructor) && (1)) {
      ParmList *l;
      l = new ParmList();
      doc_entry = new DocDecl(classname,this->de);
      cplus_constructor(classname,0,l);
    };
    
    if (!have_destructor) {
      doc_entry = new DocDecl(classname,this->de);
      cplus_destructor(classname,0);
    }
  }

  // ------------------------------------------------------------------------------
  // Dump *all* of the classes saved out to the various
  // language modules (this does what cplus_close_class used to do)
  // ------------------------------------------------------------------------------
  static void create_all();
};

CPP_class *CPP_class::classlist = 0;
static CPP_class     *current_class;

void CPP_class::create_all() {
  CPP_class *c;
  c = classlist;
  while (c) {
    if (!c->error) {
      current_class = c;
      localtypes = c->local;
      if ((!c->wextern) && (c->classtype)) {
	ObjCClass = c->objective_c;
	doc_entry = c->de;
	lang->cpp_open_class(c->classname,c->classrename,c->classtype,c->strip);
	lang->cpp_pragma(c->pragmas);
	c->create_default();
	if (c->baseclass)
	  cplus_inherit_decl(c->baseclass);
	c->emit_decls();
	doc_entry = c->de;
	lang->cpp_close_class();
      }
    }
    c = c->next;
  }
}

// -----------------------------------------------------------------------------
// char *cplus_base_class(char *name)
//
// Given a member name, return the base class that it belongs to.
// -----------------------------------------------------------------------------

char *cplus_base_class(char *name) {
  CPP_member *m = current_class->search_member(name);
  if (m) {
    return m->base;
  } 
  return 0;
}

// -----------------------------------------------------------------------------
// void cplus_open_class(char *name, char *rname, char *ctype) 
//
// Opens up a new C++ class.   If rname is given, we'll be renaming the
// class.    This also sets up some basic type equivalence for the
// type checker.
// 
// Inputs :
//          name      = Name of the class
//          rname     = New name of the class (using %name() directive)
//          ctype     = Class type ("class","struct", or "union")
//
// Output : None
//
// Side Effects :
//          Creates a new class obect internally.
//          Added type-mappings to the SWIG type-checker module.
//          Sets a number of internal state variables for later use.
//
// -----------------------------------------------------------------------------

void cplus_open_class(char *name, char *rname, char *ctype) {

  extern void typeeq_derived(char *, char *, char *cast=0);
  char temp[256];
  CPP_class *c;

  // Add some symbol table management here

  // Search for a previous class definition

  c = CPP_class::search(name);
  if (c) {
    if (c->classtype) {
      // Hmmm. We already seem to have defined this class so we'll
      // create a new class object for whatever reason
      current_class = new CPP_class(name, ctype);
    } else {
      // Looks like a reference was made to this class earlier
      // somehow, but no other information is known.  We'll
      // make it our current class and fix it up a bit
      current_class = c;
      c->classtype = copy_string(ctype);
    }
  } else {
    // Create a new class
    current_class = new CPP_class(name, ctype); 
    current_class->de = doc_entry;
  }

  // Set localtypes hash to our current class

  localtypes = current_class->local;

  // If renaming the class, set the new name

  if (rname) {
    current_class->classrename = copy_string(rname);
  }
  
  // Make a typedef for both long and short versions of this datatype

  if (name) {
    if (strlen(name)) {
      if (strlen(ctype) > 0) {
	sprintf(temp,"%s %s", ctype, name);   
	typeeq_derived(temp,name);       // Map "struct foo" to "foo"
	typeeq_derived(name,temp);       // Map "foo" to "struct foo"
      }
    }
  }

  AddMethods = 0;          // Reset add methods flag

}

// -----------------------------------------------------------------------------
// DocEntry *cplus_set_class(char *name)
//
// This function sets the current class to a given name.   If the class
// doesn't exist, this function will create one.   If it already exists,
// we'll just use that.
//
// This function is used primarily to add or manipulate an already
// existing class, but in a different location.  For example :
//
//         %include "class.h"        // Grab some classes
//         ...
//         %addmethods MyClass {     // Add some members for shadow classes
//               ... members ...
//         }
// 
// Sounds weird, but returns the documentation entry to class if it exists.
// The parser needs this so we can generate documentation correctly.
// 
// Inputs : name   = Name of the class
//
// Output : Documentation entry of class or NULL if it doesn't exist.
//          The parser needs the documentation entry to properly associate
//          new members.
//
// Side Effects :
//          Changes the current class object.  Resets a number of internal
//          state variables.  Should not be called inside of a open class
//          declaration.
// -----------------------------------------------------------------------------

DocEntry *cplus_set_class(char *name) {
  
  CPP_class *c;

  // Look for a previous class definition

  c = CPP_class::search(name);
  if (c) {
    current_class = c;
    localtypes = c->local;
    return c->de;
  } else {
    fprintf(stderr,"%s:%d:  Warning class %s undefined.\n",input_file,line_number,name);
    current_class = new CPP_class(name,0);
    localtypes = current_class->local;
    return 0;
  }
};

// This function closes a class open with cplus_set_class() 

void cplus_unset_class() {
  current_class = 0;
}

// -----------------------------------------------------------------------------
// void cplus_class_close(char *name)
//
// Close a C++ class definition.   Up to this point, we've only been collecting
// member definitions.     This function merely closes the class object and
// stores it in a list.  All classes are dumped after processing has completed.
//
// If name is non-null, it means that the name of the class has actually been
// set after all of the definitions.  For example :
//
//    typedef struct {
//             double x,y,z
//    } Vector;
//
// If this is the case, we'll use that as our classname and datatype.
// Otherwise, we'll just go with the classname and classtype set earlier.
// 
// Inputs : name   = optional "new name" for the class.
//
// Output : None
//
// Side Effects : Resets internal variables. Saves class in internal list.
//                Registers the class with the language module, but doesn't
//                emit any code.
// -----------------------------------------------------------------------------

void cplus_class_close(char *name) {

  if (name) {
    // The name of our class suddenly changed by typedef.  Fix things up
    current_class->classname = copy_string(name);

    // This flag indicates that the class needs to have it's type stripped off
    current_class->strip = 1;
  }

  // If we're in C++ or Objective-C mode. We're going to drop the class specifier

  if ((CPlusPlus) || (ObjCClass)) {
    current_class->strip = 1;
  }
  
  // Register our class with the target language module, but otherwise
  // don't do anything yet.

  char *iname;
  if (current_class->classrename) iname = current_class->classrename;
  else iname = current_class->classname;

  lang->cpp_class_decl(current_class->classname, iname, current_class->classtype);

  // Clear current class variable and reset
  current_class = 0;
  localtypes = 0;

}

// -----------------------------------------------------------------------------
// void cplus_abort(void)
//
// Voids the current class--some kind of unrecoverable parsing error occurred.
// -----------------------------------------------------------------------------

void cplus_abort(void) {
  current_class->error = 1;
  current_class = 0;
  localtypes = 0;
}

// -----------------------------------------------------------------------------
// void cplus_cleanup(void)
//
// This function is called after all parsing has been completed.  It dumps all
// of the stored classes out to the language module.
// 
// Inputs : None
//
// Output : None
//
// Side Effects : Emits all C++ wrapper code.
// -----------------------------------------------------------------------------

void cplus_cleanup(void) {

  // Dump all classes created at once (yikes!)

  CPP_class::create_all();
  lang->cpp_cleanup();
}

// -----------------------------------------------------------------------------
// void cplus_inherit(int count, char **baseclass)
//
// Inherit from a baseclass.  This function only really registers
// the inheritance, but doesn't do anything with it yet.
// 
// Inputs : baseclass  = A NULL terminated array of strings with the names
//                       of baseclasses.   For multiple inheritance, there
//                       will be multiple entries in this list.
//
// Output : None
//
// Side Effects : Sets the baseclass variable of the current class.
// -----------------------------------------------------------------------------

void cplus_inherit(int count, char **baseclass) {
  int i;

  // printf("Inheriting : count = %d, baseclass = %x\n",count,baseclass);
  // If there are baseclasses, make copy of them
  if (count) {
    current_class->baseclass = (char **) new char*[count+1];
    for (i = 0; i < count; i++) 
      current_class->baseclass[i] = copy_string(baseclass[i]);
    current_class->baseclass[i] = 0;
  } else {
    baseclass = 0;
  }
}

// -----------------------------------------------------------------------------
// cplus_generate_types(char **baseclass)
//
// Generates the type-mappings between the current class and any associated
// base classes.  This is done by performing a depth first search of the
// class hierarchy.   Functions for performing correct type-casting are
// generated for each base-derived class pair.
//
// Inputs : baseclass     = NULL terminated list of base classes
//
// Output : None
//
// Side Effects : Emits pointer conversion functions.  Registers type-mappings
//                with the type checking module.
//
// -----------------------------------------------------------------------------

static Hash convert;                // Hash table of conversion functions

void cplus_generate_types(char **baseclass) {
  CPP_class *bc;
  int        i;
  String     cfunc, temp1, temp2, temp3;
  extern void typeeq_derived(char *, char *, char *);

  if (!baseclass) {
    return;
  }

  // Generate type-conversion functions and type-equivalence

  i = 0;
  while(baseclass[i]) {
    cfunc = "";

    bc = CPP_class::search(baseclass[i]);
    if (bc) {
      // Generate a conversion function (but only for C++)

      if (!current_class->objective_c) {
	temp3 = "";
	temp3 << "Swig" << current_class->classname << "To" << bc->classname;

	if (convert.add(temp3,(void *) 1) != -1) {

	  // Write a function for casting derived type to parent class

	  cfunc << "static void *Swig" << current_class->classname << "To" << bc->classname 
		<< "(void *ptr) {\n"
		<< tab4 << current_class->classname << " *src;\n"
		<< tab4 << bc->classname << " *dest;\n"
		<< tab4 << "src = (" << current_class->classname << " *) ptr;\n"
		<< tab4 << "dest = (" << bc->classname << " *) src;\n"
	    //	    << tab4 << "printf(\"casting...\\n\");\n"
		<< tab4 << "return (void *) dest;\n"
		<< "}\n";
	  
	  fprintf(f_wrappers,"%s\n",cfunc.get());
	}
      } else {
	temp3 = "0";
      }
      
      // Make a type-equivalence allowing derived classes to be used in functions of the

      if (strlen(current_class->classtype) > 0) {
	temp1 = "";
	temp1 << current_class->classtype << " " << current_class->classname;
	temp2 = "";
	temp2 << bc->classtype << " " << bc->classname;
	// Add various equivalences to the pointer table
	
	typeeq_derived(bc->classname, current_class->classname,temp3.get());
	typeeq_derived(temp2.get(), current_class->classname,temp3.get());
	typeeq_derived(temp2.get(), temp1.get(),temp3.get());
	typeeq_derived(bc->classname, temp1.get(),temp3.get());
      } else {
	typeeq_derived(bc->classname, current_class->classname,temp3.get());
      }
      // Now traverse the hierarchy some more
      cplus_generate_types(bc->baseclass);
    }
    i++;
  }
}

// -----------------------------------------------------------------------------
// void cplus_inherit_decl(char **baseclass)
// 
// This function is called internally to handle inheritance between classes.
// Basically, we're going to generate type-checking information and call
// out to the target language to handle the inheritance.
//
// This function is only called when emitting classes to the language modules
// (after all parsing has been complete).
// 
// Inputs : baseclass   = NULL terminated list of base-class names.
//
// Output : None
//
// Side Effects : Generates type-mappings.  Calls the language-specific
//                inheritance function.
// -----------------------------------------------------------------------------

void cplus_inherit_decl(char **baseclass) {

  // If not base-classes, bail out

  if (!baseclass) return;

  Inherit_mode = 1;         
  lang->cpp_inherit(baseclass);        // Pass inheritance onto the various languages
  Inherit_mode = 0;

  // Create type-information for class hierarchy

  cplus_generate_types(baseclass);
}
// -----------------------------------------------------------------------------
// void cplus_inherit_members(char *baseclass, int mode)
//
// Inherits members from a class. This is called by specific language modules
// to bring in members from base classes.   It may or may  not be called. 
//
// This function is called with a *single* base-class, not multiple classes
// like other functions.   To do multiple inheritance, simply call this
// with each of the associated base classes.
// 
// Inputs :
//          baseclass     = Name of baseclass
//          mode          = Inheritance handling flags
//                  INHERIT_FUNC          - Import functions in base class 
//                  INHERIT_VAR           - Import variables in base class
//                  INHERIT_CONST         - Inherit constants
//                  INHERIT_ALL           - Inherit everything (grossly inefficient)
//
// Output : None
//
// Side Effects : Imports methods from base-classes into derived classes.
//             
// -----------------------------------------------------------------------------

void cplus_inherit_members(char *baseclass, int mode) {
  CPP_class *bc;

  bc = CPP_class::search(baseclass);
  if (bc) {
    bc->inherit_decls(mode);
  } else {
    fprintf(stderr,"%s:%d:  Warning.  Base class %s undefined (ignored).\n", input_file, current_class->line, baseclass);    
  }
}

// -----------------------------------------------------------------------------
// void cplus_member_func(char *name, char *iname, DataType *type, ParmList *, is_virtual)
//
// Parser entry point to creating a C++ member function.   This function primarily
// just records the function and does a few symbol table checks.
// 
// Inputs : 
//          name          = Real name of the member function
//          iname         = Renamed version (may be NULL)
//          type          = Return datatype
//          l             = Parameter list
//          is_virtual    = Set if this is a pure virtual function (ignored)
//
// Output : None
//
// Side Effects :
//          Adds member function to current class. 
// -----------------------------------------------------------------------------

void cplus_member_func(char *name, char *iname, DataType *type, ParmList *l,
		       int is_virtual) {

  CPP_function *f;
  char *temp_iname;

  // First, figure out if we're renaming this function or not

  if (!iname) 
    temp_iname = name;
  else 
    temp_iname = iname;

  // If we're in inherit mode, we need to check for duplicates.
  // Issue a warning.
    
  if (Inherit_mode) {
    if (current_class->search_member(temp_iname)) {
      return;
    }
  }
  
  // Add it to our C++ class list

  f = new CPP_function(name,temp_iname,type,l,0,is_virtual);
  f->de = doc_entry;
  current_class->add_member(f);

  // If this is a pure virtual function, the class is abstract

  if (is_virtual)
    current_class->is_abstract = 1;

}

// -----------------------------------------------------------------------------
// void cplus_constructor(char *name, char *iname, ParmList *l)
//
// Parser entry point for creating a constructor.
//
// Inputs : 
//          name  = Real name of the constructor (usually the same as the class)
//          iname = Renamed version (may be NULL)
//          l     = Parameter list
//
// Output : None
//
// Side Effects :
//          Adds a constructor to the current class.
// -----------------------------------------------------------------------------

void cplus_constructor(char *name, char *iname, ParmList *l) {

    CPP_constructor *c;

    // May want to check the naming scheme here

    c = new CPP_constructor(name,iname,l);
    c->de = doc_entry;
    current_class->add_member(c);
    current_class->have_constructor = 1;

}

// -----------------------------------------------------------------------------
// void cplus_destructor(char *name, char *iname)
//
// Parser entry point for adding a destructor.
// 
// Inputs :
//          name   = Real name of the destructor (usually same as class name)
//          iname  = Renamed version (may be NULL)
//
// Output : None
//
// Side Effects :
//          Adds a destructor to the current class
//
// -----------------------------------------------------------------------------

void cplus_destructor(char *name, char *iname) {

  CPP_destructor *d;

  d = new CPP_destructor(name,iname);
  d->de = doc_entry;
  current_class->add_member(d);
  current_class->have_destructor = 1;
}

// -----------------------------------------------------------------------------
// void cplus_variable(char *name, char *iname, DataType *t)
//
// Parser entry point for creating a new member variable.  
// 
// Inputs :
//          name  = name of the variable
//          iname = Renamed version (may be NULL)
//          t     = Datatype
//
// Output : None
//
// Side Effects :
//          Adds a member variable to the current class
// -----------------------------------------------------------------------------

void cplus_variable(char *name, char *iname, DataType *t) {

    CPP_variable *v;
    char *temp_iname;

    // If we're in inherit mode, we need to check for duplicates.

    if (iname)
      temp_iname = iname;
    else
      temp_iname = name;

    if (Inherit_mode) {
      if (current_class->search_member(temp_iname)) {
	return;
      }
    }
    
    v = new CPP_variable(name,iname,t,0);
    v->de = doc_entry;
    current_class->add_member(v);
}

// -----------------------------------------------------------------------------
// void cplus_static_func(char *name, char *iname, DataType *type, ParmList *l)
//
// Parser entry point for creating a new static member function.
// 
// Inputs :
//          name   = Real name of the function
//          iname  = Renamed version (may be NULL)
//          type   = Return datatype
//          l      = Parameter list
//
// Output : None
//
// Side Effects :
//          Adds a static function to the current class.
//
// -----------------------------------------------------------------------------

void cplus_static_func(char *name, char *iname, DataType *type, ParmList *l) {

  char *temp_iname;

  // If we're in inherit mode, we need to check for duplicates.
  
  if (iname) temp_iname = iname;
  else temp_iname = name;

  if (Inherit_mode) {
    if (current_class->search_member(iname)) {
      // Have a duplication
      return;
    }
  }

  CPP_function *f = new CPP_function(name, temp_iname, type, l, 1);
  f->de = doc_entry;
  current_class->add_member(f);
}

// -----------------------------------------------------------------------------
// void cplus_declare_const(char *name, char *iname, DataType *type, char *value)
//
// Parser entry point for creating a C++ constant (usually contained in an 
// enum).
// 
// Inputs :
//          name   = Real name of the constant
//          iname  = Renamed constant (may be NULL)
//          type   = Datatype of the constant
//          value  = String representation of the value
//
// Output : None
//
// Side Effects :
//          Adds a constant to the current class.
// -----------------------------------------------------------------------------

void cplus_declare_const(char *name, char *iname, DataType *type, char *value) {

  char *temp_iname;

  if (iname) temp_iname = iname;
  else temp_iname = name;

  // If we're in inherit mode, we need to check for duplicates.
  // Possibly issue a warning or perhaps a remapping
    
  if (Inherit_mode) {
    if (current_class->search_member(temp_iname)) {
      return;
    }
  }

  CPP_constant *c =  new CPP_constant(name, temp_iname, type, value);
  c->de = doc_entry;
  current_class->add_member(c);

  // Update this symbol in the symbol table
  update_symbol(name, type, value);

  // Add this symbol to local scope of a class
  add_local_type(name, current_class->classname);
}

// -----------------------------------------------------------------------------
// void cplus_static_var(char *name, char *iname, DataType *type)
//
// Parser entry point for adding a static variable
// 
// Inputs :
//          name  = Name of the member
//          iname = Renamed version (may be NULL)
//          type  = Datatype
//
// Output : None
//
// Side Effects :
//          Adds a static variable to the current class.
// -----------------------------------------------------------------------------

void cplus_static_var(char *name, char *iname, DataType *type) {

  char *temp_iname;
  
  if (iname) temp_iname = iname;
  else temp_iname = name;

  // If we're in inherit mode, we need to check for duplicates.
  // Possibly issue a warning or perhaps a remapping
  
  if (Inherit_mode) {
    if (current_class->search_member(temp_iname)) {
      return;
    }
  }

  CPP_variable *v = new CPP_variable(name, temp_iname, type, 1);
  v->de = doc_entry;
  current_class->add_member(v);
}

// -----------------------------------------------------------------------------
// cplus_add_pragma(char *lang, char *name, char *value)
//
// Add a pragma to a class 
// -----------------------------------------------------------------------------

void cplus_add_pragma(char *lang, char *name, char *value)
{
  Pragma *pp;
  Pragma *p = new Pragma;
  p->filename = input_file;
  p->lineno = line_number;
  p->lang = lang;
  p->name = name;
  p->value = value;
  
  if (!current_class->pragmas) {
    current_class->pragmas = p;
    return;
  }
  pp = current_class->pragmas;
  while (pp->next) {
    pp = pp->next;
  }
  pp->next = p;
}

// ------------------------------------------------------------------------------
// C++/Objective-C code generation functions
//
// The following functions are responsible for generating the wrapper functions
// for C++ and Objective-C methods and variables.  These functions are usually
// called by specific language modules, but individual language modules can
// choose to do something else.
//
// The C++ module sets a number of internal state variables before emitting various
// pieces of code.  These variables are often checked implicitly by these
// procedures even though nothing is passed on the command line.
//
// The code generator tries to be somewhat intelligent about what its doing.
// The member_hash Hash table keeps track of wrapped members and is used for
// sharing code between base and derived classes.
// -----------------------------------------------------------------------------

static Hash member_hash;  // Hash wrapping member function wrappers to scripting wrappers

// -----------------------------------------------------------------------------
// void cplus_emit_member_func(char *classname, char *classtype, char *classrename,
//                             char *mname, char *mrename, DataType *type, 
//                             ParmList *l, int mode)
//
// This is a generic function to produce a C wrapper around a C++ member function.
// This function does the following :
// 
//          1.     Create a C wrapper function
//          2.     Wrap the C wrapper function like a normal C function in SWIG
//          3.     Add the function to the scripting language
//          4.     Fill in the documentation entry
//
// Specific languages can choose to provide a different mechanism, but this
// function is used to provide a low-level C++ interface.
//
// The mode variable determines whether to create a new function or only to
// add it to the interpreter.   This is used to support the %addmethods directive
//
//        mode = 0    : Create a wrapper and add it (the normal mode)
//        mode = 1    : Assume wrapper was already made and add it to the
//                      interpreter (%addmethods mode)
//
// Wrapper functions are usually created as follows :
//
//     class Foo {
//       int bar(args)
//     }
//
//     becomes ....
//     Foo_bar(Foo *obj, args) {
//         obj->bar(args);
//     }
//
// if %addmethods mode is set AND there is supporting C code detected, make
// a function from it.  The object is always called 'obj'.
//
// Then we wrap Foo_bar().   The name "Foo_bar" is actually contained in the parameter
// cname.   This is so language modules can provide their own names (possibly for
// function overloading).
//
// This function makes no internal checks of the SWIG symbol table.  This is
// up to the caller.
// 
// Objective-C support (added 5/24/97) :
//
// If the class member function is part of an objective-C interface, everything
// works the same except that we change the calling mechanism to issue an 
// Objective-C message.
//
// Optimizations (added 12/31/97) :
//
// For automatically generated wrapper functions.   We now generate macros such
// as
//        #define Foo_bar(a,b,c)   (a->bar(b,c))
// 
// This should make the wrappers a little faster as well as reducing the amount
// of wrapper code.
//
// Inputs :
//          classname            = Name of C++ class
//          classtype            = Type of class (struct, union, class)
//          classrename          = Renamed class (if any)
//          mname                = Member name
//          mrename              = Renamed member
//          type                 = Return type of the function
//          l                    = Parameter list
//          mode                 = addmethods mode
//
// Output : None
//
// Side Effects :
//          Creates C accessor function in the wrapper file.
//          Calls the language module to create a wrapper function.
// -----------------------------------------------------------------------------

void cplus_emit_member_func(char *classname, char *classtype, char *classrename,
                            char *mname, char *mrename, DataType *type, ParmList *l,
  		            int mode) {
    Parm     *p;
    ParmList *newparms;
    int i;
    String   wrap;
    String   cname,iname;
    String   key;
    String   argname;
    char     *prefix;
    char     *prev_wrap = 0;
    char     *temp_mname;

    cname = "";
    iname = "";
    key = "";

    // First generate a proper name for the member function

    // Get the base class of this member
    if (!mrename) temp_mname = mname;
    else temp_mname = mrename;

    char *bc = cplus_base_class(temp_mname);
    if (!bc) bc = classname;
    if (strlen(bc) == 0) bc = classname;

    // Generate the name of the C wrapper function (is always the same, regardless
    // of renaming).

    cname << name_member(mname,bc);

    // Generate the scripting name of this function
    if (classrename) 
      prefix = classrename;
    else
      prefix = classname;

    if (mrename)
      iname << name_member(mrename,prefix);
    else
      iname << name_member(mname,prefix);

    // Now check to see if we have already wrapped a function like this.
    // If so, we'll just use the existing wrapper.

    key << cname << "+";
    l->print_types(key);
    //    printf("key = %s\n", (char *) key);  
    char *temp = copy_string(iname);
    if ((member_hash.add(key,temp)) == -1) {
      delete [] temp;
      prev_wrap = (char *) member_hash.lookup(key);
    }
    
    // Only generate code if an already existing wrapper doesn't exist
    
    if (!prev_wrap) {

      // If mode = 0: Then we go ahead and create a wrapper macro
    
      if (!mode) {
	cname = "";
	cname << iname;
	wrap << "#define " << cname << "(_swigobj";

	// Walk down the parameter list and Spit out arguments
	
	i = 0;
	p = l->get_first();
	while (p != 0) {
	  if ((p->t->type != T_VOID) || (p->t->is_pointer)) {
	    wrap << ",_swigarg" << i;
	    i++;
	  }
	  p = l->get_next();
	}
	
	wrap << ")  (";
	
	if (!ObjCClass) {
	  wrap << "_swigobj->" << mname << "(";         // C++ invocation
	} else { 
	  wrap << "[ _swigobj " << mname;               // Objective C invocation 
	}
	i = 0;
	p = l->get_first();
	while(p != 0) {
	  if (ObjCClass) wrap << " " << p->objc_separator;
	  if ((p->t->type != T_VOID) || (p->t->is_pointer)) {
	    wrap << "_swigarg" << i;
	    i++;
	  }
	  p = l->get_next();
	  if ((p != 0) && (!ObjCClass)) 
	    wrap << ",";
	}
	if (!ObjCClass) 
	  wrap << "))\n";
	else
	  wrap << "])\n";
	
	// Emit it
	fprintf(f_wrappers,"%s",wrap.get());
      } else {
	if (ccode) {
	  wrap << "static ";
	  if (type->is_reference) {
	    type->is_pointer--;
	  }
	  wrap << type->print_full();
	  if (type->is_reference) {
	    wrap << "&";
	    type->is_pointer++;
	  }
	  wrap << " " << cname << "(" << classtype << classname << " *self";
	  
	  // Walk down the parameter list and Spit out arguments
	  
	  p = l->get_first();
	  while (p != 0) {
	    if ((p->t->type != T_VOID) || (p->t->is_pointer)) {
	      wrap << ",";
	      if ((p->call_type & CALL_REFERENCE) || (p->t->is_reference)) {
		p->t->is_pointer--;
	      } 
	      wrap << p->t->print_full();
	      if ((p->call_type & CALL_REFERENCE) || (p->t->is_reference)) {
		p->t->is_pointer++;
	           if (p->t->is_reference)
		wrap << "&";
	      }
	      wrap << " " << p->name;
	    }
	    p = l->get_next();
	  }
	  
	  wrap << ") " << ccode; 
	  fprintf(f_wrappers,"%s\n",wrap.get());
	}
      }

      // Now add a parameter to the beginning of the function and call
      // a language specific function to add it.
      
      newparms = new ParmList(l);
      p = new Parm(0,0);
      p->t = new DataType;
      p->t->type = T_USER;
      p->t->is_pointer = 1;
      p->t->id = cpp_id;
      p->call_type = 0;
      
      sprintf(p->t->name,"%s%s", classtype,classname);
      p->name = "self";
      newparms->insert(p,0);       // Attach parameter to beginning of list
      
      // Now wrap the thing.  The name of the function is iname
      
      lang->create_function(cname, iname, type, newparms);
      delete newparms;
    } else {
      // Already wrapped this function.   Just patch it up 
      lang->create_command(prev_wrap, iname);
    }
}


// -----------------------------------------------------------------------------
// void cplus_emit_static_func(char *classname, char *classtype, char *classrename,
//                             char *mname, char *mrename, DataType *type, 
//                             ParmList *l, int mode)
//
// This is a generic function to produce a wrapper for a C++ static member function
// or an Objective-C class method.
//
// Specific languages can choose to provide a different mechanism, but this
// function is used to provide a low-level C++ interface.
//
// The mode variable determines whether to create a new function or only to
// add it to the interpreter.   This is used to support the %addmethods directive
//
//        mode = 0    : Create a wrapper and add it (the normal mode)
//        mode = 1    : Assume wrapper was already made and add it to the
//                      interpreter (%addmethods mode)
//
// Wrapper functions are usually created as follows :
//
//     class Foo {
//       static int bar(args)
//     }
//
//     becomes a command called Foo_bar()
//
// if %addmethods mode is set AND there is supporting C code detected, make
// a function from it.  
//
// Then we wrap Foo_bar().   The name "Foo_bar" is actually contained in the parameter
// cname.   This is so language modules can provide their own names (possibly for
// function overloading).
//
// This function makes no internal checks of the SWIG symbol table.  This is
// up to the caller.
// 
// Inputs :
//          classname            = Name of C++ class
//          classtype            = Type of class (struct, union, class)
//          classrename          = Renamed version of class (optional)
//          mname                = Member name
//          mrename              = Renamed member (optional)
//          type                 = Return type of the function
//          l                    = Parameter list
//          mode                 = addmethods mode
//
// Output : None
//
// -----------------------------------------------------------------------------

void cplus_emit_static_func(char *classname, char *, char *classrename,
			    char *mname, char *mrename, DataType *type, ParmList *l,
			    int mode) {
    Parm     *p;
    String   wrap;
    String   cname, iname, key;
    int      i;
    char     *prefix;
    char     *prev_wrap = 0;
    char     *temp_mname;
    
    cname = "";
    iname = "";
    key = "";

    // Generate a function name for the member function
    
    if (!mrename) temp_mname = mname;
    else temp_mname = mrename;
    char *bc = cplus_base_class(temp_mname);
    if (!bc) bc = classname;
    if (strlen(bc) == 0) bc = classname;
    
    // Generate the name of the C wrapper function 
    if ((!mode) && (!ObjCClass)) {
      cname << bc << "::" << mname;
    } else {
      cname << name_member(mname,bc);
    }

    // Generate the scripting name of this function
    if (classrename)
      prefix = classrename;
    else
      prefix = classname;

    if (mrename) 
      iname << name_member(mrename,prefix);
    else
      iname << name_member(mname,prefix);

    // Perform a hash table lookup to see if we've wrapped anything like this before

    key << cname << "+";
    l->print_types(key);
    char *temp = copy_string(iname);
    if ((member_hash.add(key,temp)) == -1) {
      delete [] temp;
      prev_wrap = (char *) member_hash.lookup(key);
    }

    if (!prev_wrap) {
      if (!((mode) || (ObjCClass))) {
	// Not an added method and not objective C, just wrap it
	lang->create_function(cname,iname, type, l);
      } else {
	// This is either an added method or an objective C class function
	//
	// If there is attached code, use it.
	// Otherwise, assume the function has been written already and
	// wrap it.
	
	wrap << "static " << type->print_full() << " " << cname << "(";
	  
	// Walk down the parameter list and Spit out arguments
	p = l->get_first();
	while (p != 0) {
	  if ((p->t->type != T_VOID) || (p->t->is_pointer)) {
	    if (p->t->is_reference) {
	      p->t->is_pointer--;
	    } 
	    wrap << p->t->print_full();
	    if (p->t->is_reference) {
	      p->t->is_pointer++;
	      wrap << "&";
	    }
	    wrap << " " << p->name;
	  }
	  p = l->get_next();
	  if (p) wrap << ",";
	}
	wrap << ") ";
	if ((mode) && (ccode)) {
	  wrap << ccode;
	} else if (ObjCClass) {
	  // This is an objective-C method
	  
	  wrap << "{\n" << tab4;
	  
	  // Emit the function call.  
	  
	  if ((type->type != T_VOID) || (type->is_pointer)) {
	    // Declare the return value
	    
	    if (type->is_reference) {
	      type->is_pointer--;
	      wrap << tab4 << type->print_full() << "& _result = ";
	      type->is_pointer++;
	    } else {
	      wrap << tab4 << type->print_type() << " _result = " << type->print_cast();
	    }
	  } else {
	    wrap << tab4;
	  }
	  wrap << "[ " << classname << " " << mname;               // Objective C invocation 
	  i = 0;
	  p = l->get_first();
	  while(p != 0) {
	    wrap << " " << p->objc_separator;
	    if ((p->t->type != T_VOID) || (p->t->is_pointer)) {
	      if (p->t->is_reference) {
		wrap << "*";
	      }
	      wrap << p->name;
	      i++;
	    }
	    p = l->get_next();
	  }
	  wrap << "];\n";
	  
	  if ((type->type != T_VOID) || (type->is_pointer)) {
	    if (type->is_reference) {
	      wrap << tab4 << "return " << type->print_cast() << " &_result;\n";
	    } else {
	      wrap << tab4 << "return _result;\n";
	    }
	  }
	  wrap << "}\n";
	}
	if (ObjCClass || (mode && ccode)) 
	  fprintf(f_wrappers,"%s\n",wrap.get());
	lang->create_function(cname,iname,type,l);
      }
    } else {
      // Already wrapped this function.   Just hook up to it.
      lang->create_command(prev_wrap, iname);
    }
}

// -----------------------------------------------------------------------------
// void cplus_emit_destructor(char *classname, char *classtype, char *classrename,
//                            char *mname, char *mrename, int mode)
//
// Emit a C wrapper around a C++ destructor.  
//
// Usually this function is used to do the following :
//     class Foo {
//       ...
//     ~Foo();
//     }
//
//     becomes ....
//     void delete_Foo(Foo *f) {
//         delete f;
//     }
//
// Then we wrap delete_Foo().
// 
// Inputs :
//          classname =       Name of the C++ class
//          classtype =       Type of class (struct,class,union)
//          classrename =     Renamed class (optional)
//          mname     =       Name of the destructor
//          mrename   =       Name of the function in the interpreter
//          mode      =       addmethods mode (0 or 1)
//
// Output : None
//
// Side Effects :
//          Creates a destructor function and wraps it.
// -----------------------------------------------------------------------------

void cplus_emit_destructor(char *classname, char *classtype, char *classrename, 
			   char *mname, char *mrename, int mode)
{
    Parm *p;
    DataType *type;
    ParmList *l;
    String    wrap;
    String    cname,iname;
    char      *prefix;

    // Construct names for the function

    if (classrename)
      prefix = classrename;
    else
      prefix = classname;
    
    cname << name_destroy(classname);
    if (mrename)
      iname << name_destroy(mrename);
    else
      iname << name_destroy(prefix);
    
    if (!mode) {
      // Spit out a helper function for this member function
      wrap << "#define " << cname << "(_swigobj) (";
      if (ObjCClass) {
	wrap << "[_swigobj " << mname << "])\n";   // Name of the member is the destructor
      } else if (CPlusPlus) 
	wrap << "delete _swigobj)\n";
      else
	wrap << "free ((char *) _swigobj))\n";
      fprintf(f_wrappers,"%s", wrap.get());
    } else {
      if (ccode) {
	wrap << "static void " << cname << "(" << classtype << classname << " *self) " << ccode;
	fprintf(f_wrappers,"%s\n",wrap.get());
      }
    }

    // Make a parameter list for this function
    
    l = new ParmList;
    p = new Parm(0,0);
    p->t = new DataType;
    p->t->type = T_USER;
    p->t->is_pointer = 1;
    p->t->id = cpp_id;
    p->call_type = 0;
    sprintf(p->t->name,"%s%s", classtype, classname);
    p->name = "self";
    l->insert(p,0);
    
    type = new DataType;
    type->type = T_VOID;
    sprintf(type->name,"void");
    type->is_pointer = 0;
    type->id = cpp_id;

    // iname is the desired name of the function in the target language

    lang->create_function(cname,iname,type,l);

    delete type;
    delete l;

}

// -----------------------------------------------------------------------------
// void cplus_emit_constructor(char *classname, char *classtype, char *classrename,
//                             char *mname, char *mrename, ParmList *l, int mode)
//
// Creates a C wrapper around a C++ constructor
//
// Inputs :
//          classname    = name of class
//          classtype    = type of class (struct,class,union)
//          classrename  = Renamed class (optional)
//          mname        = Name of constructor
//          mrename      = Renamed constructor (optional)
//          l            = Parameter list
//          mode         = addmethods mode
//
// Output : None
//
// Side Effects :
//          Creates a C wrapper and calls the language module to wrap it.
// -----------------------------------------------------------------------------

void cplus_emit_constructor(char *classname, char *classtype, char *classrename,
                            char *mname, char *mrename, ParmList *l, int mode)
{
    Parm *p;
    int i;
    DataType *type;
    String  wrap;
    String  fcall,cname,iname,argname;
    char    *prefix;

    // Construct names for the function

    if (classrename)
      prefix = classrename;
    else
      prefix = classname;
    
    cname << name_construct(classname);
    if (mrename)
      iname << name_construct(mrename);
    else
      iname << name_construct(prefix);

    // Create a return type

    type = new DataType;
    type->type = T_USER;
    sprintf(type->name,"%s%s", classtype,classname);
    type->is_pointer = 1;
    type->id = cpp_id;

    if (!mode) {
      wrap << "#define " << iname << "(";
      cname = "";
      cname << iname;
      if (ObjCClass) {
	fcall << type->print_cast() << "[" << classname << " " << mname;
      } else if (CPlusPlus) {
	fcall << "new " << classname << "(";
      } else {
	fcall << type->print_cast() << " calloc(1,sizeof(" 
	      << classtype << classname << "))";
      }

      // Walk down the parameter list and spit out arguments
      
      i = 0;
      p = l->get_first();
      while (p != 0) {
	if (ObjCClass) fcall << " " <<  p->objc_separator;
	if ((p->t->type != T_VOID) || (p->t->is_pointer)) {
	  wrap << "_swigarg" << i;

	  // Emit an argument in the function call if in C++ mode
	  
	  if ((CPlusPlus) || (ObjCClass)) {
	    fcall << "_swigarg" << i;
	  }
	}
	i++;
	p = l->get_next();
	if (p) {
	  wrap << ",";
	  if ((CPlusPlus) && (!ObjCClass))
	    fcall << ",";
	}
      }
      
      wrap << ") ";
      if (ObjCClass) fcall << "]";
      else if (CPlusPlus) fcall << ")";

      wrap << "(" << fcall << ")\n";
      fprintf(f_wrappers,"%s",wrap.get());
    } else {
      if (ccode) {
	wrap << "static " << classtype << classname << " *" << cname << "(";

	// Walk down the parameter list and spit out arguments
      
	p = l->get_first();
	while (p != 0) {
	  if ((p->t->type != T_VOID) || (p->t->is_pointer)) {
	    if (p->call_type & CALL_REFERENCE) {
	      p->t->is_pointer--;
	    }
	    wrap << p->t->print_real(p->name);
	    if (p->call_type & CALL_REFERENCE) {
	      p->t->is_pointer++;
	    }
	    p = l->get_next();
	    if (p) {
	      wrap << ",";
	    }
	  } else {
	    p = l->get_next();
	  }
	}
	wrap << ") " << ccode << "\n";
	fprintf(f_wrappers,"%s\n",wrap.get());
     }
    }

    // If we had any C++ references, get rid of them now

    if (!mode) {
      p = l->get_first();
      while (p) {
	//	p->t->is_reference = 0;
	p = l->get_next();
      } 
    }

    // We've now created a C wrapper.  We're going to add it to the interpreter

    lang->create_function(cname, iname, type, l);
    delete type;
}

// -----------------------------------------------------------------------------
// void cplus_emit_variable_get(char *classname, char *classtype, char *classrename,
//                              char *mname, char *mrename, DataType *type, int mode)
//
// Writes a C wrapper to extract a data member
//
// Usually this function works as follows :
// 
// class Foo {
//      double x;
// }
//
// becomes :
// 
// double Foo_x_get(Foo *obj) {
//      return obj->x;
// }
// 
// Optimization : 12/31/97
//
// Now emits a macro like this :
//
//      #define Foo_x_get(obj) (obj->x)
//
// Inputs :
//          classname     = name of C++ class
//          classtype     = type of class (struct, class, union)
//          classrename   = Renamed class
//          mname         = Member name
//          mrename       = Renamed member
//          type          = Datatype of the member
//          mode          = Addmethods mode
//
// Output : None
//
// Side Effects :
//          Creates a C accessor function and calls the language module
//          to make a wrapper around it.
// -----------------------------------------------------------------------------

void cplus_emit_variable_get(char *classname, char *classtype, char *classrename,
			     char *mname, char *mrename, DataType *type, int mode) {

    Parm     *p;
    ParmList *l;
    String    wrap;
    String    cname, iname, key;
    char      *prefix;
    char      *tm;
    String    source;
    char     *temp_mname;
    char     *prev_wrap = 0;

    cname = "";
    iname = "";
    key = "";

    // First generate a proper name for the get function

    // Get the base class of this member
    if (!mrename) temp_mname = mname;
    else temp_mname = mrename;

    char *bc = cplus_base_class(temp_mname);
    if (!bc) bc = classname;
    if (strlen(bc) == 0) bc = classname;

    // Generate the name of the C wrapper function (is always the same, regardless
    // of renaming).

    cname << name_get(name_member(mname,bc));

    // Generate the scripting name of this function
    if (classrename) 
      prefix = classrename;
    else
      prefix = classname;

    if (mrename)
      iname << name_get(name_member(mrename,prefix));
    else
      iname << name_get(name_member(mname,prefix));

    // Now check to see if we have already wrapped a variable like this.

    key << cname;
    char *temp = copy_string(iname);
    if ((member_hash.add(key,temp)) == -1) {
      delete [] temp;
      prev_wrap = (char *) member_hash.lookup(key);
    }

    // Only generate code if already existing wrapper doesn't exist
    if (!prev_wrap) {
      if (!mode) {
	// Get any sort of typemap that might exist

	source << "obj->" << mname;

	// Now write a function to get the value of the variable

	tm = typemap_lookup("memberout",typemap_lang,type,mname,source,"result");

	if ((type->type == T_USER) && (!type->is_pointer)) {
	  type->is_pointer++;
	  if (tm) {
	    wrap << "static " << type->print_type() << " " << cname << "(" 
		 << classtype << classname << " *obj) {\n"
		 << tab4 << type->print_type() << " result;\n"
		 << tm << "\n"
		 << tab4 << "return result;\n"
		 << "}\n";
	  } else {
	    wrap << "#define " << cname << "(_swigobj) "
		 << "(&_swigobj->" << mname << ")\n";
	  }
	  type->is_pointer--;
	} else {
	  if (tm) {
	    wrap << "static " << type->print_type() << " " << cname << "("
		 << classtype << classname << " *obj) {\n"
		 << tab4 << type->print_type() << " result;\n"
		 << tm << "\n"
		 << tab4 << "return result;\n"
		 << "}\n";
	  } else {
	    wrap << "#define " << cname << "(_swigobj) (";
	    if (!type->is_reference) wrap << type->print_cast();
	    else
	      wrap << "&";
	    wrap << " _swigobj->" << mname << ")\n";
	  }
	}
	fprintf(f_wrappers,"%s",wrap.get());
      }
      
      // Wrap this function

      l = new ParmList;
      p = new Parm(0,0);
      p->t =  new DataType;
      p->t->type = T_USER;
      p->t->is_pointer = 1;
      p->t->id = cpp_id;
      p->call_type = 0;	
      p->name = "self";
      sprintf(p->t->name,"%s%s", classtype,classname);
      l->insert(p,0);

      if ((type->type == T_USER) && (!type->is_pointer)) {
	type->is_pointer++;
	lang->create_function(cname,iname, type, l);
	type->is_pointer--;
      } else {
	int is_ref = type->is_reference;
	type->is_reference = 0;
	lang->create_function(cname,iname, type, l);
	type->is_reference = is_ref;
      }
      delete l;
    } else {
      // Already wrapped this function.  Just patch it up
      lang->create_command(prev_wrap,iname);
    }

}

// -----------------------------------------------------------------------------
// void cplus_emit_variable_set(char *classname, char *classtype, char *mname,
//                              char *cname, char *iname, DataType *type, int mode)
//
// Writes a C wrapper to set a data member
//
// Usually this function works as follows :
// 
// class Foo {
//      double x;
// }
//
// becomes :
// 
// double Foo_x_set(Foo *obj, double value) {
//      return (obj->x = value);
// }
//
// Need to handle special cases for char * and for user defined types. 
//
// 1.  char *
//
//     Will free previous contents (if any) and allocate
//     new storage.   Could be risky, but it's a reasonably
//     natural thing to do.
//
// 2.  User_Defined
//     Will assign value from a pointer. 
//     Will return a pointer to current value.
// 
//
// Optimization,  now defined as a C preprocessor macro
//
// Inputs :
//          classname     = name of C++ class
//          classtype     = type of class (struct, class, union)
//          mname         = Member name
//          cname         = Name of the C function for this (ie. Foo_bar_get)
//          iname         = Interpreter name of ths function
//          type          = Datatype of the member
//          mode          = Addmethods mode
//
// Output : None
//
// Side Effects :
//          Creates a C accessor function and calls the language module
//          to wrap it.
// -----------------------------------------------------------------------------

void cplus_emit_variable_set(char *classname, char *classtype, char *classrename,
			     char *mname, char *mrename, DataType *type, int mode) {

    Parm     *p;
    ParmList *l;
    String    wrap;
    int       is_user = 0;
    char      *tm;
    String    target;
    String    cname, iname, key;
    char      *temp_mname;
    char      *prefix;
    char      *prev_wrap = 0;

    cname = "";
    iname = "";
    key = "";

    // First generate a proper name for the get function

    // Get the base class of this member
    if (!mrename) temp_mname = mname;
    else temp_mname = mrename;

    char *bc = cplus_base_class(temp_mname);
    if (!bc) bc = classname;
    if (strlen(bc) == 0) bc = classname;

    // Generate the name of the C wrapper function (is always the same, regardless
    // of renaming).

    cname << name_set(name_member(mname,bc));

    // Generate the scripting name of this function
    if (classrename) 
      prefix = classrename;
    else
      prefix = classname;

    if (mrename)
      iname << name_set(name_member(mrename,prefix));
    else
      iname << name_set(name_member(mname,prefix));

    // Now check to see if we have already wrapped a variable like this.

    key << cname;
    char *temp = copy_string(iname);
    if ((member_hash.add(key,temp)) == -1) {
      delete [] temp;
      prev_wrap = (char *) member_hash.lookup(key);
    }

    // Only generate code if already existing wrapper doesn't exist

    if (!prev_wrap) {
      if (!mode) {
	
	target << "obj->" << mname;
	
	// Lookup any typemaps that might exist
	tm = typemap_lookup("memberin",typemap_lang,type,mname,"val",target);
	
	// First write a function to set the variable 

	if (tm) {
	  if ((type->type == T_USER) && (!type->is_pointer)) {
	    type->is_pointer++;
	    is_user = 1;
	  }
	  wrap << "static " << type->print_type() << " " << cname << "("
	       << classtype << classname << " *obj, " << type->print_real("val") << ") {\n";
	  if (is_user) {
	    type->is_pointer--;
	  }
	  wrap << tm << "\n";
	  // Return the member
	  if (is_user) type->is_pointer++;
	  wrap << tab4 << "return " << type->print_cast() << " val;\n";
	  if (is_user) type->is_pointer--;
	  wrap << "}\n";

	} else {
	  if ((type->type != T_VOID) || (type->is_pointer)){
	    if (!type->is_pointer) {

	      wrap << "#define " << cname << "(_swigobj,_swigval) (";	      
	      // Have a real value here (ie.  not a pointer).  
	      // If it's a user defined type, we'll do something special.
	      // Otherwise, just assign it.
	      
	      if (type->type != T_USER) {
		wrap << "_swigobj->" << mname << " = _swigval";
	      } else {
		wrap << "_swigobj->" << mname << " = *(_swigval)";
	      }
	      wrap << ",_swigval)\n";
	    } else {
	      // Is a pointer type here.  If string, we do something
	      // special.  Otherwise. No problem.
	      if ((type->type == T_CHAR) && (type->is_pointer == 1)) {
		String temp;
		wrap << "static " << type->print_type() << " " << cname << "("
		     << classtype << classname << " *obj, " << type->print_real("val") << ") {\n";
		temp << "obj->" << mname;
		if (CPlusPlus) {
		  wrap << tab4 << "if (" << temp << ") delete [] " << temp << ";\n"
		       << tab4 << temp << " = new char[strlen(val)+1];\n"
		       << tab4 << "strcpy((char *)" << temp << ",val);\n";
		} else {
		  wrap << tab4 << "if (obj->" << mname << ") free(obj->" << mname << ");\n"
		       << tab4 << "obj->" << mname << " = (char *) malloc(strlen(val)+1);\n"
		       << tab4 << "strcpy((char *)obj->" << mname << ",val);\n";
		}
		wrap << tab4 << "return (char *) val;\n";
		wrap << "}\n";
	      } else {
		// A normal pointer type of some sort
		wrap << "#define " << cname << "(_swigobj,_swigval) (";
		if (type->is_reference) {
		  wrap << "_swigobj->" << mname << " = *_swigval, _swigval)\n";
		} else {
		  wrap << "_swigobj->" << mname << " = _swigval,_swigval)\n";
		}
	      }
	    }
	  }
	}
      }
      fprintf(f_wrappers,"%s",wrap.get());      
      // Now wrap it.
      
      l = new ParmList;
      p = new Parm(0,0);
      p->t = new DataType(type);
      p->t->is_reference = 0;
      p->call_type = 0;	
      p->t->id = cpp_id;
      if ((type->type == T_USER) && (!type->is_pointer)) p->t->is_pointer++;
      if (mrename) 
	p->name = mrename;
      else
	p->name = mname;
      l->insert(p,0);
      p = new Parm(0,0);
      p->t =  new DataType;
      p->t->type = T_USER;
      p->call_type = 0;	
      p->t->is_pointer = 1;
      p->t->id = cpp_id;
      sprintf(p->t->name,"%s%s", classtype,classname);
      p->name = "self";
      l->insert(p,0);
      
      if ((type->type == T_USER) && (!type->is_pointer)) {
	type->is_pointer++;
	lang->create_function(cname,iname, type, l);
	type->is_pointer--;
      } else {
	int is_ref = type->is_reference;
	type->is_reference = 0;
	lang->create_function(cname,iname, type, l);
	type->is_reference = is_ref;
      }
      delete l;
    } else {
      lang->create_command(prev_wrap,iname);
    } 
}

// -----------------------------------------------------------------------------
// void cplus_support_doc(String &f)
//
// This function adds a supporting documentation entry to the
// end of a class.   This should only be used if there is an
// alternative interface available or if additional information is needed.
//
// doc_entry should be set to the class entry before calling this. Otherwise,
// who knows where this text is going to end up!
// 
// Inputs : f  = String with additional text
//
// Output : None
//
// Side Effects :
//          Adds a text block to the current documentation entry.
//
// -----------------------------------------------------------------------------

void cplus_support_doc(String &f) {

  DocEntry *de;
  if (doc_entry) {
    de = new DocText(f.get(),doc_entry);
    de->format = 0;
  }
}

// -----------------------------------------------------------------------------
// void cplus_register_type(char *typename)
// 
// Registers a datatype name to be associated with the current class.  This
// typename is placed into a local hash table for later use.  For example :
//
//     class foo {
//        public:
//            enum ENUM { ... };
//            typedef double Real;
//            void bar(ENUM a, Real b);      
//     }
//
// Then we need to access bar using fully qualified type names such as
//
//     void wrap_bar(foo::ENUM a, foo::Real b) {
//          bar(a,b);
//     }
//
// Inputs : name of the datatype.
//
// Output : None
//
// Side Effects : Adds datatype to localtypes.
// -----------------------------------------------------------------------------

void cplus_register_type(char *tname) {
  if (current_class)
    add_local_type(tname, current_class->classname);
};

// -----------------------------------------------------------------------------
// void cplus_register_scope(Hash *h) 
// 
// Saves the scope associated with a particular class.  It will be needed
// later if anything inherits from us.
//
// Inputs : Hash table h containing the scope
//
// Output : None
//
// Side Effects : Saves h with current class
// -----------------------------------------------------------------------------

void cplus_register_scope(Hash *h) {
  if (current_class) {
    current_class->scope = h;
  }
}

// -----------------------------------------------------------------------------
// void cplus_inherit_scope(int count, char **baseclass) 
// 
// Given a list of base classes, this function extracts their former scopes
// and merges them with the current scope.  This is needed to properly handle
// inheritance.
//
// Inputs : baseclass = NULL terminated array of base-class names
//
// Output : None
//
// Side Effects : Updates current scope with new symbols.
//
// Copies any special symbols if needed.
// -----------------------------------------------------------------------------

void cplus_inherit_scope(int count, char **baseclass) {
  CPP_class *bc;
  int i;
  char *key, *val;
  String str;

  if (count && current_class) {
    for (i = 0; i < count; i++) {
       bc = CPP_class::search(baseclass[i]);
      if (bc) {
	if (bc->scope)
	  DataType::merge_scope(bc->scope);

	if (bc->local) {
	  // Copy local symbol table
	  key = bc->local->firstkey();
	  while (key) {
	    val = (char *) bc->local->lookup(key);
	    str = val;
	    //	    str.replace(bc->classname,current_class->classname);
	    localtypes->add(key,copy_string(str));
	    key = bc->local->nextkey();
	  }
	}
      }
    }
  }
}

