/* -----------------------------------------------------------------------------
 * cwrap.c
 *
 *     This file defines a variety of wrapping rules for C/C++ handling including
 *     the naming of local variables, calling conventions, and so forth.
 *
 * Author(s) : David Beazley (beazley@cs.uchicago.edu)
 *
 * Copyright (C) 1998-2000.  The University of Chicago
 * Copyright (C) 1995-1998.  The University of Utah and The Regents of the
 *                           University of California.
 *
 * See the file LICENSE for information on usage and redistribution.
 * ----------------------------------------------------------------------------- */

char cvsroot_cwrap_c[] = "$Header: /cvsroot/CableSwig/CableSwig/SWIG/Source/Swig/cwrap.c,v 1.1.1.1 2003/04/09 17:34:11 hoffman Exp $";

#include "swig.h"

static Parm *nonvoid_parms(Parm *p) {
  if (p) {
    SwigType *t = Getattr(p,"type");
    if (SwigType_type(t) == T_VOID) return 0;
  }
  return p;
}

/* -----------------------------------------------------------------------------
 * Swig_parm_name()
 *
 * Generates a name for the ith argument in an argument list
 * ----------------------------------------------------------------------------- */

String *
Swig_cparm_name(Parm *p, int i) {
  String *name = NewStringf("arg%d",i+1);
  if (p) {
    Setattr(p,"lname",name);
  }
  return name;
}

/* -----------------------------------------------------------------------------
 * Swig_clocal()
 *
 * Creates a string that declares a C local variable type.  Converts references
 * and user defined types to pointers.
 * ----------------------------------------------------------------------------- */

String *
Swig_clocal(SwigType *t, String_or_char *name, String_or_char *value) {
  String *decl;

  decl = NewString("");

  switch(SwigType_type(t)) {
  case T_REFERENCE:
    if (value) {
      Printf(decl,"%s = (%s) &%s_defvalue", SwigType_lstr(t,name), SwigType_lstr(t,0), name);
    } else {
      Printf(decl,"%s = 0", SwigType_lstr(t,name));
    }
    break;
  case T_VOID:
    break;
  case T_VARARGS:
    Printf(decl,"void *%s = 0", name);
    break;

  default:
    if (value) {
      Printf(decl,"%s = (%s) %s", SwigType_lstr(t,name), SwigType_lstr(t,0), SwigType_lcaststr(t,value));
    } else {
      Printf(decl,"%s", SwigType_lstr(t,name));
    }
  }
  return decl;
}

/* -----------------------------------------------------------------------------
 * Swig_wrapped_var_convert()
 *
 * Converts a member variable for use in the get and set wrapper methods.
 * This function only converts user defined types to pointers.
 * ----------------------------------------------------------------------------- */

String *
Swig_wrapped_var_type(SwigType *t) {
  SwigType *ty;
  ty = Copy(t);

  if (SwigType_isclass(t)) {
    SwigType_add_pointer(ty);
  }
  return ty;
}

String *
Swig_wrapped_var_deref(SwigType *t, String_or_char *name) {
  if (SwigType_isclass(t)) {
    return NewStringf("*%s",name);
  } else {
    return SwigType_rcaststr(t,name);
  }
}

String *
Swig_wrapped_var_assign(SwigType *t, String_or_char *name) {
  if (SwigType_isclass(t)) {
    return NewStringf("&%s",name);
  } else {
    return SwigType_lcaststr(t,name);
  }
}

/* -----------------------------------------------------------------------------
 * Swig_cargs()
 *
 * Emit all of the local variables for a list of parameters.  Returns the
 * number of parameters.
 * ----------------------------------------------------------------------------- */

int Swig_cargs(Wrapper *w, ParmList *p) {
  int   i;
  SwigType *pt;
  String  *pvalue;
  String  *pname;
  String  *local;
  String  *lname;
  SwigType *altty;
  String  *type;
  int      tycode;

  i = 0;
  while (p != 0) {
    lname  = Swig_cparm_name(p,i);
    pt     = Getattr(p,"type");
    if ((SwigType_type(pt) != T_VOID)) {
      pname  = Getattr(p,"name");
      pvalue = Getattr(p,"value");
      altty = Getattr(p,"alttype");
      type  = Getattr(p,"type");
      tycode = SwigType_type(type);
      if (tycode == T_REFERENCE) {
	if (pvalue) {
	  String *defname, *defvalue;
	  defname = NewStringf("%s_defvalue", lname);
	  defvalue = NewStringf("%s = %s", SwigType_str(type,defname), pvalue);
	  Wrapper_add_localv(w,defname, defvalue, NIL);
	  Delete(defname);
	  Delete(defvalue);
	}
      }  else if (!pvalue && (tycode == T_POINTER)) {
	pvalue = (String *) "0";
      }
      if (!altty) {
	local  = Swig_clocal(pt,lname,pvalue);
      } else {
	local = Swig_clocal(altty,lname, pvalue);
      }
      Wrapper_add_localv(w,lname,local,NIL);
      i++;
    }
    p = nextSibling(p);
  }
  return(i);
}

/* -----------------------------------------------------------------------------
 * Swig_cresult()
 *
 * This function generates the C code needed to set the result of a C
 * function call.  
 * ----------------------------------------------------------------------------- */

String *Swig_cresult(SwigType *t, const String_or_char *name, const String_or_char *decl) {
  String *fcall;
  
  fcall = NewString("");
  switch(SwigType_type(t)) {
  case T_VOID:
    break;
  case T_REFERENCE:
    Printf(fcall,"{\n");
    Printf(fcall,"%s = ", SwigType_str(t,"_result_ref"));
    break;
  case T_USER:
    Printf(fcall,"%s = ", name);
    break;

  default:
    /* Normal return value */
    Printf(fcall,"%s = (%s)", name, SwigType_lstr(t,0));
    break;
  }

  /* Now print out function call */
  Printv(fcall,decl,NIL);

  /* A sick hack */
  {
    char *c = Char(decl) + Len(decl) - 1;
    if (!((*c == ';') || (*c == '}')))
      Printf(fcall, ";");
  }
  Printf(fcall,"\n");

  if (SwigType_type(t) == T_REFERENCE) {
    Printf(fcall,"%s = (%s) &_result_ref;\n", name, SwigType_lstr(t,0));
    Printf(fcall,"}\n");
  }
  return fcall;
}

/* -----------------------------------------------------------------------------
 * Swig_cfunction_call()
 *
 * Creates a string that calls a C function using the local variable rules
 * defined above.
 *
 *    name(arg0, arg1, arg2, ... argn)
 *
 * ----------------------------------------------------------------------------- */

String *
Swig_cfunction_call(String_or_char *name, ParmList *parms) {
  String *func;
  int i = 0;
  int comma = 0;
  Parm *p = parms;
  SwigType *pt;
  String  *nname;

  func = NewString("");
  nname = SwigType_namestr(name);
  Printf(func,"%s(", nname);
  while (p) {
    String *pname;
    pt = Getattr(p,"type");

    if ((SwigType_type(pt) != T_VOID)) {
      if (comma) Printf(func,",");
      pname = Swig_cparm_name(p,i);
      Printf(func,"%s", SwigType_rcaststr(pt, pname));
      comma = 1;
      i++;
    }
    p = nextSibling(p);
  }
  Printf(func,")");
  return func;
}

/* -----------------------------------------------------------------------------
 * Swig_cmethod_call()
 *
 * Generates a string that calls a C++ method from a list of parameters.
 * 
 *    arg0->name(arg1, arg2, arg3, ..., argn)
 *
 * self is an argument that defines how to handle the first argument. Normally,
 * it should be set to "this->".  With C++ proxy classes enabled, it could be
 * set to "(*this)->" or some similar sequence.
 * ----------------------------------------------------------------------------- */

String *
Swig_cmethod_call(String_or_char *name, ParmList *parms, String_or_char *self) {
  String *func, *nname;
  int i = 0;
  Parm *p = parms;
  SwigType *pt;
  int comma = 0;

  if (!self) self = (char *) "(this)->";

  func = NewString("");
  nname = SwigType_namestr(name);
  if (!p) return func;
  Append(func,self);
  pt = Getattr(p,"type");

  /* If the method is invoked through a dereferenced pointer, we don't add any casts
     (needed for smart pointers).  Otherwise, we cast to the appropriate type */

  if (Strstr(func,"*this")) {
    Replaceall(func,"this", Swig_cparm_name(p,0));
  } else {
    Replaceall(func,"this", SwigType_rcaststr(pt, Swig_cparm_name(p,0)));
  }

  if (SwigType_istemplate(name)) {
      Printf(func,"template %s(", nname);
  } else {
      Printf(func,"%s(", nname);
  }
  i++;
  p = nextSibling(p);
  while (p) {
    String *pname;
    pt = Getattr(p,"type");
    if ((SwigType_type(pt) != T_VOID)) {
      if (comma) Printf(func,",");
      pname = Swig_cparm_name(p,i);
      Printf(func,"%s", SwigType_rcaststr(pt, pname));
      comma = 1;
      i++;
    }
    p = nextSibling(p);
  }
  Printf(func,")");
  Delete(nname);
  return func;
}

/* -----------------------------------------------------------------------------
 * Swig_cconstructor_call()
 *
 * Creates a string that calls a C constructor function.
 *
 *      (name *) calloc(1,sizeof(name));
 * ----------------------------------------------------------------------------- */

String *
Swig_cconstructor_call(String_or_char *name) {
  DOH *func;

  func = NewString("");
  Printf(func,"(%s *) calloc(1, sizeof(%s))", name, name);
  return func;
}


/* -----------------------------------------------------------------------------
 * Swig_cppconstructor_call()
 *
 * Creates a string that calls a C function using the local variable rules
 * defined above.
 *
 *    name(arg0, arg1, arg2, ... argn)
 *
 * ----------------------------------------------------------------------------- */

String *
Swig_cppconstructor_call(String_or_char *name, ParmList *parms) {
  String *func;
  String *nname;
  int i = 0;
  int comma = 0;
  Parm *p = parms;
  SwigType *pt;
  nname = SwigType_namestr(name);
  func = NewString("");
  Printf(func,"new %s(", nname);
  while (p) {
    String *pname;
    pt = Getattr(p,"type");
    if ((SwigType_type(pt) != T_VOID)) {
      if (comma) Printf(func,",");
      pname = Swig_cparm_name(p,i);
      Printf(func,"%s", SwigType_rcaststr(pt, pname));
      comma = 1;
      i++;
    }
    p = nextSibling(p);
  }
  Printf(func,")");
  Delete(nname);
  return func;
}


/* -----------------------------------------------------------------------------
 * Swig_cdestructor_call()
 *
 * Creates a string that calls a C constructor function.
 *
 *      free((char *) arg0);
 * ----------------------------------------------------------------------------- */

String *
Swig_cdestructor_call() {
  String *func;
  func = NewString("");
  Printf(func,"free((char *) %s)", Swig_cparm_name(0,0));
  return func;
}


/* -----------------------------------------------------------------------------
 * Swig_cppdestructor_call()
 *
 * Creates a string that calls a C constructor function.
 *
 *      delete arg0;
 * ----------------------------------------------------------------------------- */

String *
Swig_cppdestructor_call() {
  String *func;

  func = NewString("");
  Printf(func,"delete %s", Swig_cparm_name(0,0));
  return func;
}

/* -----------------------------------------------------------------------------
 * Swig_cmemberset_call()
 *
 * Generates a string that sets the name of a member in a C++ class or C struct.
 *
 *        arg0->name = arg1
 *
 * ----------------------------------------------------------------------------- */

String *
Swig_cmemberset_call(String_or_char *name, SwigType *type, String_or_char *self) {
  String *func;
  func = NewString("");
  if (!self) self = NewString("(this)->");
  else self = NewString(self);
  Replaceall(self,"this",Swig_cparm_name(0,0));
  if (SwigType_type(type) != T_ARRAY) {
    Printf(func,"if (%s) %s%s = %s",Swig_cparm_name(0,0), self,name, Swig_wrapped_var_deref(type, Swig_cparm_name(0,1)));
  }
  Delete(self);
  return(func);
}


/* -----------------------------------------------------------------------------
 * Swig_cmemberget_call()
 *
 * Generates a string that sets the name of a member in a C++ class or C struct.
 *
 *        arg0->name
 *
 * ----------------------------------------------------------------------------- */

String *
Swig_cmemberget_call(String_or_char *name, SwigType *t, String_or_char *self) {
  String *func;
  if (!self) self = NewString("(this)->");
  else self = NewString(self);
  Replaceall(self,"this",Swig_cparm_name(0,0));
  func = NewString("");
  Printf(func,"%s (%s%s)", Swig_wrapped_var_assign(t,""),self, name);
  Delete(self);
  return func;
}

/* -----------------------------------------------------------------------------
 * Swig_MethodToFunction(Node *n)
 *
 * Converts a C++ method node to a function accessor function.
 * ----------------------------------------------------------------------------- */

int
Swig_MethodToFunction(Node *n, String *classname, int flags) {
  String   *name, *qualifier;
  ParmList *parms;
  SwigType *type;
  Parm     *p;
  String   *self = 0;

  /* If smart pointer, change self derefencing */
  if (flags & CWRAP_SMART_POINTER) {
    self = NewString("(*this)->");
  }
  /* If node is a member template expansion, we don't allow added code */

  if (Getattr(n,"templatetype")) flags &= ~(CWRAP_EXTEND);

  name      = Getattr(n,"name");
  qualifier = Getattr(n,"qualifier");
  parms     = CopyParmList(nonvoid_parms(Getattr(n,"parms")));
  
  type = NewString(classname);
  if (qualifier) {
    SwigType_push(type,qualifier);
  }
  SwigType_add_pointer(type);
  p = NewParm(type,"self");
  Setattr(p,"hidden","1");
  set_nextSibling(p,parms);
  Delete(type);
  
  /* Generate action code for the access */
  if (!(flags & CWRAP_EXTEND)) {
    Setattr(n,"wrap:action", Swig_cresult(Getattr(n,"type"),"result", Swig_cmethod_call(name,p,self)));
  } else {
    String *code;
    String *mangled;
    String *membername = Swig_name_member(classname, name);
    mangled = Swig_name_mangle(membername);

    code = Getattr(n,"code");
    type = Getattr(n,"type");

    /* Check if the method is overloaded.   If so, and it has code attached, we append an extra suffix
       to avoid a name-clash in the generated wrappers.  This allows overloaded methods to be defined
       in C. */

    if (Getattr(n,"sym:overloaded") && code) {
      Append(mangled,Getattr(n,"sym:overname"));
    }

    Setattr(n,"wrap:action", Swig_cresult(Getattr(n,"type"),"result", Swig_cfunction_call(mangled,p)));

    /* See if there is any code that we need to emit */
    if (code) {
      String *body;
      String *tmp = NewStringf("%s(%s)", mangled, ParmList_str(p));
      body = SwigType_str(type,tmp);
      Delete(tmp);
      Printv(body,code,"\n",NIL);
      Setattr(n,"wrap:code",body);
    }
    Delete(membername);
    Delete(mangled);
  }
  Setattr(n,"parms",p);
  Delete(p);
  Delete(self);
  return SWIG_OK;
}

/* -----------------------------------------------------------------------------
 * Swig_ConstructorToFunction()
 *
 * This function creates a C wrapper for a C constructor function. 
 * ----------------------------------------------------------------------------- */

int
Swig_ConstructorToFunction(Node *n, String *classname, int cplus, int flags)
{
  ParmList *parms;
  SwigType *type;
  String   *membername;
  String   *mangled;
  membername = Swig_name_construct(classname);
  mangled = Swig_name_mangle(membername);

  parms = CopyParmList(nonvoid_parms(Getattr(n,"parms")));
  type  = NewString(classname);
  SwigType_add_pointer(type);

  if (flags & CWRAP_EXTEND) {
    String *code = Getattr(n,"code");
    if (code) {
      String *wrap;
      String *s = NewStringf("%s(%s)", mangled, ParmList_str(parms));
      wrap = SwigType_str(type,s);
      Delete(s);
      Printv(wrap,code,"\n",NIL);
      Setattr(n,"wrap:code",wrap);
      Delete(wrap);
    }
    Setattr(n,"wrap:action", Swig_cresult(type,"result", Swig_cfunction_call(mangled,parms)));
  } else {
    if (cplus) {
      Setattr(n,"wrap:action", Swig_cresult(type,"result", Swig_cppconstructor_call(classname,parms)));
    } else {
      Setattr(n,"wrap:action", Swig_cresult(type,"result", Swig_cconstructor_call(classname)));
    }
  }
  Setattr(n,"type",type);
  Setattr(n,"parms", parms);
  Delete(type);
  Delete(parms);
  Delete(mangled);
  Delete(membername);
  return SWIG_OK;
}

/* -----------------------------------------------------------------------------
 * Swig_DestructorToFunction()
 *
 * This function creates a C wrapper for a destructor function.
 * ----------------------------------------------------------------------------- */

int
Swig_DestructorToFunction(Node *n, String *classname, int cplus, int flags)
{
  SwigType *type;
  Parm     *p;

  type  = NewString(classname);
  SwigType_add_pointer(type);
  p = NewParm(type,"self");
  Delete(type);
  type = NewString("void");

  if (flags & CWRAP_EXTEND) {
    String *membername, *mangled, *code;
    membername = Swig_name_destroy(classname);
    mangled = Swig_name_mangle(membername);
    code = Getattr(n,"code");
    if (code) {
      String *s = NewStringf("void %s(%s)", mangled, ParmList_str(p));
      Printv(s,code,"\n",NIL);
      Setattr(n,"wrap:code",s);
      Delete(s);
    }
    Setattr(n,"wrap:action", NewStringf("%s;\n", Swig_cfunction_call(mangled,p)));
    Delete(membername);
    Delete(mangled);
  } else {
    if (cplus) {
      Setattr(n,"wrap:action", NewStringf("%s;\n", Swig_cppdestructor_call()));
    } else {
      Setattr(n,"wrap:action", NewStringf("%s;\n", Swig_cdestructor_call()));
    }
  }
  Setattr(n,"type",type);
  Setattr(n,"parms", p);
  Delete(type);
  Delete(p);
  return SWIG_OK;
}

/* -----------------------------------------------------------------------------
 * Swig_MembersetToFunction()
 *
 * This function creates a C wrapper for setting a structure member.
 * ----------------------------------------------------------------------------- */

int
Swig_MembersetToFunction(Node *n, String *classname, int flags) {
  String   *name;
  ParmList *parms;
  Parm     *p;
  SwigType *t;
  SwigType *ty;
  SwigType *type;
  String   *membername;
  String   *mangled;
  String   *self= 0;

  if (flags & CWRAP_SMART_POINTER) {
    self = NewString("(*this)->");
  }

  name = Getattr(n,"name");
  type = Getattr(n,"type");

  membername = Swig_name_member(classname, Swig_name_set(name));
  mangled = Swig_name_mangle(membername);

  t = NewString(classname);
  SwigType_add_pointer(t);
  parms = NewParm(t,"self");
  Delete(t);

  ty = Swig_wrapped_var_type(type);
  p = NewParm(ty,name);
  set_nextSibling(parms,p);

  /* If the type is a pointer or reference.  We mark it with a special wrap:disown attribute */
  if (SwigType_check_decl(type,"p.")) {
    Setattr(p,"wrap:disown","1");
  }
  Delete(p);

  if (flags & CWRAP_EXTEND) {
    String *code = Getattr(n,"code");
    if (code) {
      String *s = NewStringf("void %s(%s)", mangled, ParmList_str(parms));
      Printv(s,code,"\n",NIL);
      Setattr(n,"wrap:code",s);
      Delete(s);
    }
    Setattr(n,"wrap:action", NewStringf("%s;\n", Swig_cfunction_call(mangled,parms)));
  } else {
    Setattr(n,"wrap:action", NewStringf("%s;\n", Swig_cmemberset_call(name,type,self)));
  }
  Setattr(n,"type","void");
  Setattr(n,"parms", parms);
  Delete(parms);
  Delete(ty);
  Delete(membername);
  Delete(mangled);
  Delete(self);
  return SWIG_OK;
}

/* -----------------------------------------------------------------------------
 * Swig_MembergetToFunction()
 *
 * This function creates a C wrapper for setting a structure member.
 * ----------------------------------------------------------------------------- */

int
Swig_MembergetToFunction(Node *n, String *classname, int flags) {
  String   *name;
  ParmList *parms;
  SwigType *t;
  SwigType *ty;
  SwigType *type;
  String   *membername;
  String   *mangled;
  String   *self = 0;

  if (flags & CWRAP_SMART_POINTER) {
    self = NewString("(*this)->");
  }

  name = Getattr(n,"name");
  type = Getattr(n,"type");

  membername = Swig_name_member(classname, Swig_name_get(name));
  mangled = Swig_name_mangle(membername);

  t = NewString(classname);
  SwigType_add_pointer(t);
  parms = NewParm(t,"self");
  Delete(t);

  ty = Swig_wrapped_var_type(type);
  if (flags & CWRAP_EXTEND) {
    String *code = Getattr(n,"code");
    if (code) {
      String *tmp = NewStringf("%s(%s)", mangled, ParmList_str(parms));
      String *s = SwigType_str(ty,tmp);
      Delete(tmp);
      Printv(s,code,"\n",NIL);
      Setattr(n,"wrap:code",s);
      Delete(s);
    }
    Setattr(n,"wrap:action", Swig_cresult(ty,"result",Swig_cfunction_call(mangled,parms)));
  } else {
    Setattr(n,"wrap:action", Swig_cresult(ty,"result",Swig_cmemberget_call(name,type,self)));
  }
  Setattr(n,"type",ty);
  Setattr(n,"parms", parms);
  Delete(parms);
  Delete(ty);
  Delete(membername);
  Delete(mangled);
  return SWIG_OK;
}

/* -----------------------------------------------------------------------------
 * Swig_VarsetToFunction()
 *
 * This function creates a C wrapper for setting a global variable.
 * ----------------------------------------------------------------------------- */

int
Swig_VarsetToFunction(Node *n) {
  String   *name,*nname;
  ParmList *parms;
  SwigType *type, *ty;

  name = Getattr(n,"name");
  type = Getattr(n,"type");

  nname = SwigType_namestr(name);

  ty = Swig_wrapped_var_type(type);
  parms = NewParm(ty,"value");
  Delete(ty);
  
  Setattr(n,"wrap:action", NewStringf("%s = %s;\n", nname, Swig_wrapped_var_deref(type,Swig_cparm_name(0,0))));
  Setattr(n,"type","void");
  Setattr(n,"parms",parms);
  Delete(parms);
  Delete(nname);
  return SWIG_OK;
}

/* -----------------------------------------------------------------------------
 * Swig_VargetToFunction()
 *
 * This function creates a C wrapper for getting a global variable.
 * ----------------------------------------------------------------------------- */

int
Swig_VargetToFunction(Node *n) {
  String   *name, *nname;
  SwigType *type, *ty;

  name = Getattr(n,"name");
  type = Getattr(n,"type");

  nname = SwigType_namestr(name);
  ty = Swig_wrapped_var_type(type);

  Setattr(n,"wrap:action", Swig_cresult(ty,"result",Swig_wrapped_var_assign(type,nname)));
  Setattr(n,"type",ty);
  Delattr(n,"parms");
  Delete(nname);
  Delete(ty);
  return SWIG_OK;
}
