/*******************************************************************************
 * 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"
#include <ctype.h>


// -----------------------------------------------------------------------
// $Header: /cvsroot/SWIG1.1/SWIG/lang.cxx,v 1.3 1999/08/13 19:34:18 beazley Exp $
//
// lang.cxx
//
// This file contains some default methods for the SWIG language class.   
// Default C++ handling is implemented here as well as a few utility functions.
//
// -----------------------------------------------------------------------


// -----------------------------------------------------------------
// void Language::set_init(char *iname)
//
// Called to make an initialization function by %init (obsolete)
// ----------------------------------------------------------------- 

void Language::set_init(char *iname) {
  set_module(iname,0);
}

// -----------------------------------------------------------------
// void Language::create_command(char *cname, char *iname
//
// Method for adding a previous wrapped C function.
// ----------------------------------------------------------------- 

void Language::create_command(char *, char *) {
  fprintf(stderr,"SWIG Warning. No command creation procedure defined.\n");
  fprintf(stderr,"C++ inheritance may not work correctly.\n");
}

// -----------------------------------------------------------------
// void Language::add_native(char *targetlang, char *funcname)
//
// Method for adding a native function
// ----------------------------------------------------------------- 

void
Language::add_native(char *, char *funcname) {

  fprintf(stderr,"%s : Line %d.  Adding native function %s not supported (ignored).\n", input_file, line_number, funcname);

}

static char  *ClassName = 0;        // This is the real name of the current class
static char  *ClassRename = 0;      // This is non-NULL if the class has been renamed
static char  *ClassType = 0;        // Type of class (ie. union, struct, class) 

// ---------------------------------------------------------------------------------
// void Language::cpp_open_class(char *classname, char *classrename, char *ctype, int strip)
//
// Open a new C++ class.
//
// INPUTS:
//      classname          = Real name of the C++ class
//      classrename        = New name of the class (if %name was used)
//      ctype              = Class type (struct, class, union, etc...)
//      strip              = Flag indicating whether we should strip the class type off
//
// This function is in charge of creating a new class.   The SWIG parser has
// already processed the entire class definition prior to calling this
// function (which should simplify things considerably).
//
// ---------------------------------------------------------------------------------

void Language::cpp_open_class(char *classname, char *classrename, char *ctype, int strip) {

  // Copy the class name

  if (ClassName) delete ClassName;
  ClassName = copy_string(classname);

  // Copy the class renaming

  if (ClassRename) delete ClassRename;
  if (classrename) {
    ClassRename = copy_string(classrename);
  } else {
    ClassRename = 0;           // No renaming
  }

  // Make the class type

  if (ClassType) delete ClassType;
  ClassType = new char[strlen(ctype)+2];
  if (strip) ClassType[0] = 0;
  else sprintf(ClassType,"%s ",ctype);

  if (doc_entry) {
    doc_entry->usage = "";
    doc_entry->name = copy_string(classname);
    doc_entry->usage << "class ";
    if (ClassRename) doc_entry->usage << ClassRename;
    else doc_entry->usage << ClassName;
    doc_entry->cinfo << "created from " << ctype 
		     << " " << classname;
  }
}

// ---------------------------------------------------------------------------------
// void Language::cpp_close_class()
//
// Close the current class
// ---------------------------------------------------------------------------------

void Language::cpp_close_class() {


  // Doesn't really do anything 
}

// ---------------------------------------------------------------------------------
// void Language::cpp_member_func(char *name, char *iname, DataType *t, ParmList *l)
//
// Method for adding C++ member function
//
// INPUTS:
//      name        - name of the member function
//      iname       - renaming (if given)
//      t           - Return datatype
//      l           - Parameter list
//
// By default, we're going to create a function of the form :
//
//         Foo_bar(this,args)
//
// Where Foo is the classname, bar is the member name and the this pointer is
// explicitly attached to the beginning.
//
// The renaming only applies to the member function part, not the full classname.
//
// ---------------------------------------------------------------------------------

void Language::cpp_member_func(char *name, char *iname, DataType *t, ParmList *l) {
  char       cname[256];       // Name of the C function
  char       new_name[256];
  char       *prefix;

  // Generate the C wrapper function name and interpreter name of this function
  
  // Set the classname prefix
  if (ClassRename) {
    prefix = ClassRename;
  } else {
    prefix = ClassName;
  }

  // Generate the C wrapper name for this method
  
  if (AddMethods) {
    char *bc = cplus_base_class(name);         // Get base class name of this method
    if (bc)
      strcpy(cname, name_member(name,bc));
    else
      strcpy(cname, name_member(name,ClassName));
  } else {
    strcpy(cname, name_member(name,ClassName));
  }

  // Create the actual function name

  if (iname) {
    strcpy(new_name, name_member(iname, prefix));
  } else {
    strcpy(new_name, name_member(name,prefix));
  }

  // Now do a symbol table lookup on it :

  if (add_symbol(new_name, 0,0)) {
    fprintf(stderr,"%s : Line %d. Function %s (member %s) multiply defined (2nd definition ignored).\n",
	    input_file, line_number, cname, name);
    return;
  }
  
  // Now produce the resulting wrapper function
  if (doc_entry) {
    doc_entry->cinfo << "Member : ";
  }
  cplus_emit_member_func(ClassName, ClassType, ClassRename, name, iname, t, l, AddMethods);
}

// ---------------------------------------------------------------------------------
// void Language::cpp_constructor(char *name, char *iname, ParmList *l)
//
// Method for adding C++ member constructor
//
// INPUTS:
//      name           - Name of the constructor (usually same as classname)
//      iname          - Renamed version
//      l              - parameters
// ---------------------------------------------------------------------------------

void Language::cpp_constructor(char *name, char *iname, ParmList *l) {

  char *prefix, *cname;

  if ((strcmp(name,ClassName)) && (!ObjCClass)) {
    fprintf(stderr,"%s : Line %d.  Function %s must have a return type.\n", 
	    input_file, line_number, name);
    return;
  }

  // Set the prefix

  if (ClassRename)
    prefix = ClassRename;
  else
    prefix = ClassName;

  if (iname)
    cname = name_construct(iname);
  else
    cname = name_construct(prefix);

  // Add this function to the SWIG symbol table

  if (add_symbol(cname, 0,0)) {
    fprintf(stderr,"%s : Line %d. Constructor %s multiply defined (2nd definition ignored).\n",
	    input_file, line_number, cname);
    return;
  }

  // Attach a note to the cinfo field.

  if (doc_entry) 
    doc_entry->cinfo << "Constructor: ";

  // Call our default method

  cplus_emit_constructor(ClassName, ClassType, ClassRename, name, iname, l, AddMethods);

}

// ---------------------------------------------------------------------------------
// void Language::cpp_destructor(char *name, char *iname)
//
// Method for adding C++ member destructor
//
// INPUT:
//     name        -  Name of the destructor (classname)
//     iname       -  Renamed destructor
//
// ---------------------------------------------------------------------------------

void Language::cpp_destructor(char *name, char *iname) {

  char *cname;

  if (ClassRename) 
    cname = name_destroy(ClassRename);
  else
    cname = name_destroy(ClassName);

  // Add this function to the SWIG symbol table

  if (add_symbol(cname, 0,0)) {
    fprintf(stderr,"%s : Line %d. Destructor %s multiply defined (2nd definition ignored).\n",
	    input_file, line_number, cname);
    return;
  }


  // Attach a note to the description

  if (doc_entry)
    doc_entry->cinfo << "Destructor: ";

  // Call our default method

  cplus_emit_destructor(ClassName, ClassType, ClassRename, name, iname, AddMethods);

}

// ---------------------------------------------------------------------------------
// void Language::cleanup()
//
// Perform any necessary cleanup after reaching end of interface file
// ---------------------------------------------------------------------------------

void Language::cpp_cleanup() {

  // This doesn't do anything (well, not be default)

}

// ---------------------------------------------------------------------------------
// void Language::cpp_inherit(char **baseclass, int mode)
//
// Inherit attributes from given baseclass.  
//
// INPUT:
//     baseclass       = NULL terminate list of baseclasses
//
// ---------------------------------------------------------------------------------

void Language::cpp_inherit(char **baseclass, int mode) {
  
  extern void cplus_inherit_members(char *, int);
  int    i = 0;

  if (!baseclass) return;
  while (baseclass[i]) {
    cplus_inherit_members(baseclass[i],mode);
    i++;
  }
}

// ---------------------------------------------------------------------------------
// void Language::cpp_variable(char *name, char *iname, DataType *t)
//
// Wrap a C++ data member
//
// INPUTS :
//      name       = Name of the C++ member
//     iname       = Name as used in the interpreter
//         t       = Datatype
//
// This creates a pair of functions to set/get the variable of a member.
// ---------------------------------------------------------------------------------

void Language::cpp_variable(char *name, char *iname, DataType *t) {
  char *prefix, *cname;

  // Set the class prefix
  
  if (ClassRename) {
    prefix = ClassRename;
  } else {
    prefix = ClassName;
  }

  if (iname)
    cname = name_get(name_member(iname,prefix));
  else
    cname = name_get(name_member(name,prefix));

  // Check the symbol table

  if (add_symbol(cname,(DataType *) 0,(char *) 0)) {
    fprintf(stderr,"%s : Line %d. Variable %s multiply defined (2nd definition ignored).\n", input_file, line_number, cname);
    return;
  }

  // Attach a c descriptor

  if (doc_entry)
    doc_entry->cinfo << "Member data: ";

  // Create a function to set the value of the variable

  if (!(Status & STAT_READONLY)) {
    cplus_emit_variable_set(ClassName, ClassType, ClassRename, name, iname, t, AddMethods);
    // Add a new line to the documentation entry
    if (doc_entry) doc_entry->usage << "\n";
  }

  // Create a function to get the value of a variable

  cplus_emit_variable_get(ClassName,ClassType, ClassRename, name, iname, t, AddMethods);

}

// ---------------------------------------------------------------------------------
// void Language::cpp_static_func(char *name, char *iname, DataType *t, ParmList *l)
//
// Wrap a static C++ function
//
// INPUTS:
//      name           = Real name of the function
//     iname           = New name in interpreter
//      t              = Return datatype
//      l              = Parameters
// ---------------------------------------------------------------------------------

void Language::cpp_static_func(char *name, char *iname, DataType *t, ParmList *l) {

  char  *prefix;
  char  *mname;
  char  *cname;

  // Set the classname prefix
  
  if (ClassRename) 
    prefix = ClassRename;
  else
    prefix = ClassName;

  // Set the member function name

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

  cname = name_member(mname,prefix);

  // Now do a symbol table lookup on it :

  if (add_symbol(cname, 0,0)) {
    if (ObjCClass)
      fprintf(stderr,"%s : Line %d. class function %s multiply defined (2nd definition ignored).\n",
	      input_file, line_number, cname);
    else
      fprintf(stderr,"%s : Line %d. static function %s multiply defined (2nd definition ignored).\n",
	      input_file, line_number, cname);
    return;
  }

  if (doc_entry) {
    if (ObjCClass)
      doc_entry->cinfo << "Class method : ";
    else
      doc_entry->cinfo << "Static member : ";
  }

  cplus_emit_static_func(ClassName,ClassType, ClassRename, name, iname, t, l, AddMethods);

}

// ---------------------------------------------------------------------------------
// void Language::cpp_declare_const(char *name, char *iname, DataType *t, char *value)
//
// Create a C++ constant
//
// INPUTS :
//       name          = Real name of the constant
//       iname         = new name
//       t             = Datatype
//       value         = value as a string
//
// ---------------------------------------------------------------------------------

void Language::cpp_declare_const(char *name, char *iname, DataType *type, char *value)
{

  char  *cname;
  char  mname[256];
  char  *new_value;
  char  *prefix;

  // Set the classname prefix
  
  if (ClassRename) {
    prefix = ClassRename;
  } else {
    prefix = ClassName;
  }

  // Set the constant name

  if (iname)
    cname = name_member(iname,prefix);
  else
    cname = name_member(name,prefix);

  // Now do a symbol table lookup on it :

  if (add_symbol(cname, 0,0)) {
    fprintf(stderr,"%s : Line %d. Constant %s (member %s) multiply defined (2nd definition ignored).\n",
	    input_file, line_number, cname, name);
    return;
  }

  // Form correct C++ name

  sprintf(mname,"%s::%s",ClassName,name);

  // Declare a constant
  if (!value) {
    new_value = new char[strlen(ClassName)+strlen(name)+3];
    sprintf(new_value,"%s::%s",ClassName,name);
  } else {
    new_value = value;
  }

  lang->declare_const(cname,cname,type, new_value);
  
  if (!value) {
    delete new_value;
  }
}

// ---------------------------------------------------------------------------------
// void Language::cpp_static_var(char *name, char *iname, DataType *t)
//
// Wrap a static C++ variable
//
// INPUT :
//      name        = name of the variable
//     iname        = interpreter name
//         t        = Datatype
//
// ---------------------------------------------------------------------------------

void Language::cpp_static_var(char *name, char *iname, DataType *t) {

  char  *cname;
  char  mname[256];
  char  *prefix;

  // Set the classname prefix
  
  if (ClassRename) {
    prefix = ClassRename;
  } else {
    prefix = ClassName;
  }

  // Create the variable name
  
  if (iname) 
    cname = name_member(iname,prefix);
  else
    cname = name_member(name,prefix);

  // Now do a symbol table lookup on it :

  if (add_symbol(cname, 0,0)) {
    fprintf(stderr,"%s : Line %d. Variable %s (member %s) multiply defined (2nd definition ignored).\n",
	    input_file, line_number, cname, name);
    return;
  }

  // Form correct C++ name

  sprintf(mname,"%s::%s",ClassName,name);

  if (doc_entry)
    doc_entry->cinfo << "Static member : ";

  // Link with this variable

  lang->link_variable(mname,cname,t);
}

// ---------------------------------------------------------------------------------
// void Language::cpp_class_decl(char *classtype, char *classrename, char *classname)
//
// A forward class declaration
// ---------------------------------------------------------------------------------

void Language::cpp_class_decl(char *, char *, char *) {

  // Does nothing by default

}

// -----------------------------------------------------------------------------
// void Language::cpp_pragma(Pragma *plist)
//
// Handler C++ pragmas
// -----------------------------------------------------------------------------

void Language::cpp_pragma(Pragma *) {
  // Does nothing by default
}

// ---------------------------------------------------------------------------------
// void Language::add_typedef(DataType *t, char *name)
//
// Process a typedef declaration.
// ---------------------------------------------------------------------------------

void Language::add_typedef(DataType *, char *) {

}


// ---------------------------------------------------------------------------------
// void Language::pragma(char *target, char *var, char *value)
//
// A pragma declaration
// ---------------------------------------------------------------------------------

void Language::pragma(char *, char *, char *) {

  // Does nothing by default

}

// ---------------------------------------------------------------------------------
// void Language::import(char *filename)
//
// An import directive
// ---------------------------------------------------------------------------------

void Language::import(char *) {

  // Does nothing by default

}









