#include "orbit-c-backend.h"
#include <ctype.h>
#include <glib.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

/* Abbreviations used here:
   "cbe" stands for "C backend"
   "hdr" -> "header" (duh :)
   "of" -> "output file"
   "ns" -> "name space"
*/

typedef struct {
  FILE *of;
  IDL_ns ns;
  IDL_tree tree;
} CBEHeaderInfo;

static void orbit_cbe_hdr_process_piece(CBEHeaderInfo *hinfo);
static void cbe_hdr_do_none(CBEHeaderInfo *hinfo);
static void cbe_hdr_do_list(CBEHeaderInfo *hinfo);
static void cbe_hdr_do_gentree(CBEHeaderInfo *hinfo);
static void cbe_hdr_do_integer(CBEHeaderInfo *hinfo);
static void cbe_hdr_do_string(CBEHeaderInfo *hinfo);
static void cbe_hdr_do_wide_string(CBEHeaderInfo *hinfo);
static void cbe_hdr_do_char(CBEHeaderInfo *hinfo);
static void cbe_hdr_do_wide_char(CBEHeaderInfo *hinfo);
static void cbe_hdr_do_fixed(CBEHeaderInfo *hinfo);
static void cbe_hdr_do_float(CBEHeaderInfo *hinfo);
static void cbe_hdr_do_boolean(CBEHeaderInfo *hinfo);
static void cbe_hdr_do_ident(CBEHeaderInfo *hinfo);
static void cbe_hdr_do_type_dcl(CBEHeaderInfo *hinfo);
static void cbe_hdr_do_const_dcl(CBEHeaderInfo *hinfo);
static void cbe_hdr_do_except_dcl(CBEHeaderInfo *hinfo);
static void cbe_hdr_do_attr_dcl(CBEHeaderInfo *hinfo);
static void cbe_hdr_do_inherited_attr_dcl(CBEHeaderInfo *hinfo, IDL_tree current_interface);
static void cbe_hdr_do_op_dcl(CBEHeaderInfo *hinfo);
static void cbe_hdr_do_inherited_op_dcl(CBEHeaderInfo *hinfo, IDL_tree current_interface);
static void cbe_hdr_do_param_dcl(CBEHeaderInfo *hinfo);
static void cbe_hdr_do_forward_dcl(CBEHeaderInfo *hinfo);
static void cbe_hdr_do_type_integer(CBEHeaderInfo *hinfo);
static void cbe_hdr_do_type_float(CBEHeaderInfo *hinfo);
static void cbe_hdr_do_type_fixed(CBEHeaderInfo *hinfo);
static void cbe_hdr_do_type_char(CBEHeaderInfo *hinfo);
static void cbe_hdr_do_type_wide_char(CBEHeaderInfo *hinfo);
static void cbe_hdr_do_type_string(CBEHeaderInfo *hinfo);
static void cbe_hdr_do_type_wide_string(CBEHeaderInfo *hinfo);
static void cbe_hdr_do_type_boolean(CBEHeaderInfo *hinfo);
static void cbe_hdr_do_type_octet(CBEHeaderInfo *hinfo);
static void cbe_hdr_do_type_any(CBEHeaderInfo *hinfo);
static void cbe_hdr_do_type_object(CBEHeaderInfo *hinfo);
static void cbe_hdr_do_type_typecode(CBEHeaderInfo *hinfo);
static void cbe_hdr_do_type_enum(CBEHeaderInfo *hinfo);
static void cbe_hdr_do_type_sequence(CBEHeaderInfo *hinfo);
static void cbe_hdr_do_type_array(CBEHeaderInfo *hinfo);
static void cbe_hdr_do_type_struct(CBEHeaderInfo *hinfo);
static void cbe_hdr_do_type_union(CBEHeaderInfo *hinfo);
static void cbe_hdr_do_member(CBEHeaderInfo *hinfo);
static void cbe_hdr_do_case_stmt(CBEHeaderInfo *hinfo);
static void cbe_hdr_do_interface(CBEHeaderInfo *hinfo);
static void cbe_hdr_do_module(CBEHeaderInfo *hinfo);
static void cbe_hdr_do_binop(CBEHeaderInfo *hinfo);
static void cbe_hdr_do_unaryop(CBEHeaderInfo *hinfo);
static void cbe_hdr_do_native(CBEHeaderInfo *hinfo);

void
orbit_cbe_write_header(FILE *outfile, IDL_ns ns, IDL_tree tree)
{
  CBEHeaderInfo hinfo;

  hinfo.of = outfile;
  hinfo.ns = ns;
  hinfo.tree = tree;

  g_return_if_fail(IDL_NODE_TYPE(tree) == IDLN_LIST);

  fprintf(outfile, "/*\n"
  		   " * This file was generated by orbit-idl - DO NOT EDIT!\n"
		   " */\n\n");
  fprintf(outfile, "#include <glib.h>\n");
  fprintf(outfile, "#define ORBIT_IDL_SERIAL %d\n", ORBIT_SERIAL);
  fprintf(outfile, "#include <orb/orbit.h>\n\n");

  fprintf(outfile, "#ifdef __cplusplus\n");
  fprintf(outfile, "extern \"C\" {\n");
  fprintf(outfile, "#endif /* __cplusplus */\n\n");

  orbit_cbe_hdr_process_piece(&hinfo);

  fprintf(outfile, "#ifdef __cplusplus\n");
  fprintf(outfile, "}\n");
  fprintf(outfile, "#endif /* __cplusplus */\n\n");

  fprintf(outfile, "#undef ORBIT_IDL_SERIAL\n");
}

static void
orbit_cbe_hdr_process_piece(CBEHeaderInfo *hinfo)
{
  /* I'm not implementing this as an array of function pointers
     because we may want to do special logic for particular cases in
     the future. Hope this is clear enough. -ECL */

  switch(IDL_NODE_TYPE(hinfo->tree)) {
  case IDLN_ATTR_DCL:
    cbe_hdr_do_attr_dcl(hinfo);
    break;
  case IDLN_BINOP:
    cbe_hdr_do_binop(hinfo);
    break;
  case IDLN_BOOLEAN:
    cbe_hdr_do_boolean(hinfo);
    break;
  case IDLN_CASE_STMT:
    cbe_hdr_do_case_stmt(hinfo);
    break;
  case IDLN_CHAR:
    cbe_hdr_do_char(hinfo);
    break;
  case IDLN_CONST_DCL:
    cbe_hdr_do_const_dcl(hinfo);
    break;
  case IDLN_EXCEPT_DCL:
    cbe_hdr_do_except_dcl(hinfo);
    break;
  case IDLN_FIXED:
    cbe_hdr_do_fixed(hinfo);
    break;
  case IDLN_FLOAT:
    cbe_hdr_do_float(hinfo);
    break;
  case IDLN_FORWARD_DCL:
    cbe_hdr_do_forward_dcl(hinfo);
    break;
  case IDLN_GENTREE:
    cbe_hdr_do_gentree(hinfo);
    break;
  case IDLN_IDENT:
    cbe_hdr_do_ident(hinfo);
    break;
  case IDLN_INTEGER:
    cbe_hdr_do_integer(hinfo);
    break;
  case IDLN_INTERFACE:
    cbe_hdr_do_interface(hinfo);
    break;
  case IDLN_LIST:
    cbe_hdr_do_list(hinfo);
    break;
  case IDLN_MEMBER:
    cbe_hdr_do_member(hinfo);
    break;
  case IDLN_MODULE:
    cbe_hdr_do_module(hinfo);
    break;
  case IDLN_NONE:
    cbe_hdr_do_none(hinfo);
    break;
  case IDLN_OP_DCL:
    cbe_hdr_do_op_dcl(hinfo);
    break;
  case IDLN_PARAM_DCL:
    cbe_hdr_do_param_dcl(hinfo);
    break;
  case IDLN_STRING:
    cbe_hdr_do_string(hinfo);
    break;
  case IDLN_TYPE_ANY:
    cbe_hdr_do_type_any(hinfo);
    break;
  case IDLN_TYPE_ARRAY:
    cbe_hdr_do_type_array(hinfo);
    break;
  case IDLN_TYPE_BOOLEAN:
    cbe_hdr_do_type_boolean(hinfo);
    break;
  case IDLN_TYPE_CHAR:
    cbe_hdr_do_type_char(hinfo);
    break;
  case IDLN_TYPE_DCL:
    cbe_hdr_do_type_dcl(hinfo);
    break;
  case IDLN_TYPE_ENUM:
    cbe_hdr_do_type_enum(hinfo);
    break;
  case IDLN_TYPE_FIXED:
    cbe_hdr_do_type_fixed(hinfo);
    break;
  case IDLN_TYPE_FLOAT:
    cbe_hdr_do_type_float(hinfo);
    break;
  case IDLN_TYPE_INTEGER:
    cbe_hdr_do_type_integer(hinfo);
    break;
  case IDLN_TYPE_OBJECT:
    cbe_hdr_do_type_object(hinfo);
    break;
  case IDLN_TYPE_OCTET:
    cbe_hdr_do_type_octet(hinfo);
    break;
  case IDLN_TYPE_SEQUENCE:
    cbe_hdr_do_type_sequence(hinfo);
    break;
  case IDLN_TYPE_STRING:
    cbe_hdr_do_type_string(hinfo);
    break;
  case IDLN_TYPE_STRUCT:
    cbe_hdr_do_type_struct(hinfo);
    break;
  case IDLN_TYPE_UNION:
    cbe_hdr_do_type_union(hinfo);
    break;
  case IDLN_TYPE_WIDE_CHAR:
    cbe_hdr_do_type_wide_char(hinfo);
    break;
  case IDLN_TYPE_WIDE_STRING:
    cbe_hdr_do_type_wide_string(hinfo);
    break;
  case IDLN_UNARYOP:
    cbe_hdr_do_unaryop(hinfo);
    break;
  case IDLN_WIDE_CHAR:
    cbe_hdr_do_wide_char(hinfo);
    break;
  case IDLN_WIDE_STRING:
    cbe_hdr_do_wide_string(hinfo);
    break;
  case IDLN_ANY:
    g_error("IDLN_ANY not handled!");
    break;
  case IDLN_NATIVE:
    cbe_hdr_do_native(hinfo);
    break;
  case IDLN_TYPE_TYPECODE:
    cbe_hdr_do_type_typecode(hinfo);
    break;
  default:
    /* Should never get these */
    g_error("orbit_cbe_hdr_process_piece: Unhandled node type %s (%d)",
	    IDL_NODE_TYPE_NAME(hinfo->tree), IDL_NODE_TYPE(hinfo->tree));
    break;
  }
}

static void
cbe_hdr_do_module(CBEHeaderInfo *hinfo)
{
  char *id, *idupper;
  int i;

  id = IDL_ns_ident_to_qstring(IDL_IDENT_TO_NS(IDL_MODULE(hinfo->tree).ident), "_", 0);
  g_return_if_fail(id != NULL);
  idupper = g_malloc(strlen(id) + 1);

  for(i = 0; id[i]; i++)
    idupper[i] = toupper(id[i]);
  idupper[i] = '\0';

#if 0
  fprintf(hinfo->of, "#ifndef __%s__\n#define __%s__ 1\n", idupper, idupper);
#endif
  fprintf(hinfo->of, "/* Begin CORBA module %s */\n\n", id);

  hinfo->tree = IDL_MODULE(hinfo->tree).definition_list;
  cbe_hdr_do_list(hinfo);
  
  fprintf(hinfo->of, "/* End CORBA module %s */\n", id);  
#if 0
  fprintf(hinfo->of, "#endif /* __%s__ */\n\n", idupper);
#endif
  g_free(id); g_free(idupper);
}

static void
cbe_hdr_do_none(CBEHeaderInfo *hinfo)
{
  g_assert(!"Not yet implemented");
}

static void
cbe_hdr_do_list(CBEHeaderInfo *hinfo)
{
  IDL_tree curitem;

  for(curitem = hinfo->tree; curitem; curitem = IDL_LIST(curitem).next) {
    hinfo->tree = IDL_LIST(curitem).data;
    orbit_cbe_hdr_process_piece(hinfo);
    fprintf(hinfo->of, "\n");
  }
}

static void
cbe_hdr_do_gentree(CBEHeaderInfo *hinfo)
{
  g_assert(!"Not yet implemented");
}

static void
cbe_hdr_do_integer(CBEHeaderInfo *hinfo)
{
  g_assert(!"Not yet implemented");
}

static void
cbe_hdr_do_string(CBEHeaderInfo *hinfo)
{
  g_assert(!"Not yet implemented");
}

static void
cbe_hdr_do_wide_string(CBEHeaderInfo *hinfo)
{
  g_assert(!"Not yet implemented");
}

static void
cbe_hdr_do_char(CBEHeaderInfo *hinfo)
{
  g_assert(!"Not yet implemented");
}

static void
cbe_hdr_do_wide_char(CBEHeaderInfo *hinfo)
{
  g_assert(!"Not yet implemented");
}

static void
cbe_hdr_do_fixed(CBEHeaderInfo *hinfo)
{
  g_assert(!"Not yet implemented");
}

static void
cbe_hdr_do_float(CBEHeaderInfo *hinfo)
{
  g_assert(!"Not yet implemented");
}

static void
cbe_hdr_do_boolean(CBEHeaderInfo *hinfo)
{
  g_assert(!"Not yet implemented");
}

static void
cbe_hdr_do_ident(CBEHeaderInfo *hinfo)
{
  char *id;

  id = IDL_ns_ident_to_qstring(IDL_IDENT_TO_NS(hinfo->tree), "_", 0);
  fprintf(hinfo->of, "typedef void *%s;\n", id);
  g_free(id);
}

static void
cbe_hdr_do_type_dcl(CBEHeaderInfo *hinfo)
{
  CBEHeaderInfo child_hinfo = *hinfo;
  IDL_tree curitem;
  char *id;

  for(curitem = IDL_TYPE_DCL(hinfo->tree).dcls;
      curitem; curitem = IDL_LIST(curitem).next) {

    if(IDL_NODE_TYPE(IDL_LIST(curitem).data) == IDLN_IDENT) {
      id = IDL_ns_ident_to_qstring(IDL_IDENT_TO_NS(IDL_LIST(curitem).data),
				   "_", 0);
      fprintf(hinfo->of, "#ifndef _%s_defined\n"
			 "#define _%s_defined\n\n", id, id);
      fprintf(hinfo->of, "typedef ");
      g_free(id);
    } else if(IDL_NODE_TYPE(IDL_LIST(curitem).data) == IDLN_TYPE_ARRAY) {
      id = IDL_ns_ident_to_qstring(IDL_IDENT_TO_NS(IDL_TYPE_ARRAY(IDL_LIST(curitem).data).ident), "_", 0);

      /* This is messy - the corresponding endif gets written in
       * cbe_hdr_do_type_array
       */
      fprintf(hinfo->of, "#ifndef _%s_defined\n"
			 "#define _%s_defined\n\n", id, id);
      fprintf(hinfo->of, "typedef ");
      g_free(id);
    } else {
      fprintf(hinfo->of, "/* not IDLN_IDENT or IDLN_TYPE_ARRAY - check carefully */\n");
    }

    if(IDL_NODE_TYPE(IDL_TYPE_DCL(hinfo->tree).type_spec)
       == IDLN_TYPE_SEQUENCE) {

      /* write_typespec prints out type names,
	 which is not what we want here... */
      child_hinfo.tree = IDL_TYPE_DCL(hinfo->tree).type_spec;
      orbit_cbe_hdr_process_piece(&child_hinfo);

    } else
      orbit_cbe_write_typespec(hinfo->of,
			       IDL_TYPE_DCL(hinfo->tree).type_spec);

    if(IDL_NODE_TYPE(IDL_LIST(curitem).data) == IDLN_IDENT) {

      id = IDL_ns_ident_to_qstring(IDL_IDENT_TO_NS(IDL_LIST(curitem).data),
				   "_", 0);
      fprintf(hinfo->of, " %s;\n", id);
      fprintf(hinfo->of, "#endif /* !_%s_defined */\n\n", id);
      fprintf(hinfo->of, "extern const struct CORBA_TypeCode_struct TC_%s_struct;\n", id);
      fprintf(hinfo->of, "#define TC_%s (&TC_%s_struct)\n", id, id);

      switch(IDL_NODE_TYPE(IDL_TYPE_DCL(hinfo->tree).type_spec)) {

      case IDLN_TYPE_SEQUENCE:
	fprintf(hinfo->of, "extern ");
	orbit_cbe_write_typespec(hinfo->of, IDL_TYPE_SEQUENCE(IDL_TYPE_DCL(hinfo->tree).type_spec).simple_type_spec);
	fprintf(hinfo->of,
		"* CORBA_sequence_");
	orbit_cbe_write_typename(hinfo->of, IDL_TYPE_SEQUENCE(IDL_TYPE_DCL(hinfo->tree).type_spec).simple_type_spec);
	fprintf(hinfo->of, "_allocbuf(CORBA_unsigned_long len);\n");

      default:
	fprintf(hinfo->of, "extern %s* %s__alloc(void);\n", id, id);
	if(IDL_NODE_TYPE(IDL_LIST(curitem).data) != IDLN_TYPE_ARRAY
	   && IDL_NODE_TYPE(IDL_TYPE_DCL(hinfo->tree).type_spec) != IDLN_TYPE_SEQUENCE) {
	  fprintf(hinfo->of, "#define %s__free ", id);
	  orbit_cbe_write_typename(hinfo->of,
				   IDL_TYPE_DCL(hinfo->tree).type_spec);
	  fprintf(hinfo->of, "__free\n");
	} else
	  fprintf(hinfo->of, "extern gpointer %s__free(gpointer mem, gpointer dat, CORBA_boolean free_strings); /* ORBit internals */\n ", id);
      }

      g_free(id);

    } else {
      child_hinfo.tree = IDL_LIST(curitem).data;
      orbit_cbe_hdr_process_piece(&child_hinfo);
    }

  }
}

static void
cbe_hdr_do_const_dcl(CBEHeaderInfo *hinfo)
{
  char *id;

  id = IDL_ns_ident_to_qstring(IDL_IDENT_TO_NS(IDL_CONST_DCL(hinfo->tree).ident), "_", 0);
  fprintf(hinfo->of, "#ifndef %s\n", id);
  fprintf(hinfo->of, "#define %s ", id);

  orbit_cbe_write_const(hinfo->of,
			IDL_CONST_DCL(hinfo->tree).const_exp);
  fprintf(hinfo->of, "\n");
  fprintf(hinfo->of, "#endif /* !%s */\n\n", id);

  g_free(id);
}

static void
cbe_hdr_do_except_dcl(CBEHeaderInfo *hinfo)
{
  char *id;
  IDL_tree curitem;
  CBEHeaderInfo child_hinfo = *hinfo;

  id =
    IDL_ns_ident_to_qstring(IDL_IDENT_TO_NS(IDL_EXCEPT_DCL(hinfo->tree).ident),
			    "_", 0);
  fprintf(hinfo->of, "#ifndef _%s_defined\n"
		     "#define _%s_defined\n\n", id, id);
  fprintf(hinfo->of, "typedef struct %s {\n", id);
  
  if (IDL_EXCEPT_DCL(hinfo->tree).members) {
    for(curitem = IDL_EXCEPT_DCL(hinfo->tree).members; curitem;
        curitem = IDL_LIST(curitem).next) {
      child_hinfo.tree = IDL_LIST(curitem).data;
      orbit_cbe_hdr_process_piece(&child_hinfo);
      fprintf(hinfo->of, "\n");
    }
  }
  else
    fprintf(hinfo->of, "	int empty_struct_member;\n");

  fprintf(hinfo->of, "} %s;\n", id);
  fprintf(hinfo->of, "#define ex_%s \"%s\"\n", id,
	  IDL_IDENT(IDL_EXCEPT_DCL(hinfo->tree).ident).repo_id);
  fprintf(hinfo->of, "#endif /* !_%s_defined */\n\n", id);
  fprintf(hinfo->of, "extern const struct CORBA_TypeCode_struct TC_%s_struct;\n", id);
  fprintf(hinfo->of, "#define TC_%s (&TC_%s_struct)\n", id, id);
  fprintf(hinfo->of, "extern %s* %s__alloc(void);\n", id, id);
  fprintf(hinfo->of, "extern gpointer %s__free(gpointer mem, gpointer dat, CORBA_boolean free_strings); /* ORBit internals */\n", id);

  g_free(id);
}

static void
cbe_hdr_do_attr_dcl_internal(CBEHeaderInfo *hinfo, IDL_tree current_interface, gboolean inherited)
{
  IDL_tree curop, curitem;
  GString *attrname = g_string_new(NULL);
  CBEHeaderInfo subhinfo = *hinfo;

  for(curitem = IDL_ATTR_DCL(hinfo->tree).simple_declarations;
      curitem; curitem = IDL_LIST(curitem).next) {

    /* Fake the attribute get/set methods as operation declarations */
    IDL_tree ident, ns_data_save;
    int i;

    for (i = 0; i < 2; ++i) {

	    if (i && IDL_ATTR_DCL(hinfo->tree).f_readonly)
		    break;
	    /* Output the operation on this attribute */
	    g_string_sprintf(attrname, i ? "_set_%s" : "_get_%s",
			     IDL_IDENT(IDL_LIST(curitem).data).str);
	    ident = IDL_ident_new(g_strdup(attrname->str));
	    
	    /* Tell the ident where our namespace node is, and request a return value
	       if this is the _get operation */
	    IDL_IDENT_TO_NS(ident) = IDL_IDENT_TO_NS(IDL_LIST(curitem).data);
	    curop = IDL_op_dcl_new(0, i == 0 ?
				   IDL_ATTR_DCL(hinfo->tree).param_type_spec : NULL,
				   ident, NULL, NULL, NULL);
	    
	    curop->up = hinfo->tree->up;
	    subhinfo.tree = curop;
	    
	    /* Save the namespace ident (IDL_GENTREE data) reference, assign
	       back to the temporary tree, output the operation, then restore
	       the namespace ident link */
	    ns_data_save = IDL_GENTREE(IDL_IDENT_TO_NS(IDL_LIST(curitem).data)).data;
	    IDL_GENTREE(IDL_IDENT_TO_NS(IDL_LIST(curitem).data)).data = ident;

	    if (i) {
		    /* The set routine also needs the value, so we
		       temporarily add that to the operation
		       declaration */
		    IDL_OP_DCL(curop).parameter_dcls = IDL_list_new(
			    IDL_param_dcl_new(IDL_PARAM_IN,
					      IDL_ATTR_DCL(hinfo->tree).param_type_spec,
					      IDL_ident_new(g_strdup("value"))));
	    }
	    
	    if(inherited==TRUE)
	      cbe_hdr_do_inherited_op_dcl(&subhinfo, current_interface);
	    else
	      orbit_cbe_hdr_process_piece(&subhinfo);

	    /* Restore the fake link to the original in the namespace */
	    IDL_GENTREE(IDL_IDENT_TO_NS(IDL_LIST(curitem).data)).data = ns_data_save;

	    if (i) {
		    /* Free only what we've created for the fake node, so remove 
		       the attribute node element and then free the rest */
		    IDL_PARAM_DCL(IDL_LIST(
			    IDL_OP_DCL(curop).parameter_dcls).data).param_type_spec = NULL;
	    }
	    
	    /* Remove what we've "borrowed" from ATTR_DCL from the
	       fake curop node then free the rest */
	    IDL_OP_DCL(curop).op_type_spec = NULL;
	    IDL_tree_free(curop);
    }
  }

  g_string_free(attrname, TRUE);
}

static void
cbe_hdr_do_attr_dcl(CBEHeaderInfo *hinfo)
{
  cbe_hdr_do_attr_dcl_internal(hinfo, NULL, FALSE);
}

static void
cbe_hdr_do_inherited_attr_dcl(CBEHeaderInfo *hinfo, IDL_tree current_interface)
{
  if(enable_inherited_ops)
    cbe_hdr_do_attr_dcl_internal(hinfo, current_interface, TRUE);
}

static void
cbe_hdr_do_op_dcl(CBEHeaderInfo *hinfo)
{
  /* If you fix anything here, please also fix it in
     cbe_hdr_interface_print_epv_for_op(), which is almost a
     cut-and-paste of this routine */

  char *id, *id2;
  IDL_tree curitem, op;

  id = IDL_ns_ident_to_qstring(IDL_IDENT_TO_NS(IDL_OP_DCL(hinfo->tree).ident), "_", 0);
  curitem = IDL_get_parent_node(hinfo->tree, IDLN_INTERFACE, NULL);
  g_assert(curitem);
  id2 = IDL_ns_ident_to_qstring(IDL_IDENT_TO_NS(IDL_INTERFACE(curitem).ident), "_", 0);

  fprintf(hinfo->of, "extern ");

  orbit_cbe_write_typespec(hinfo->of, IDL_OP_DCL(hinfo->tree).op_type_spec);
  orbit_cbe_param_printptrs(hinfo->of, IDL_OP_DCL(hinfo->tree).op_type_spec, DATA_RETURN);

  fprintf(hinfo->of, " %s(%s _obj, ", id, id2);

  op = hinfo->tree;
  for(curitem = IDL_OP_DCL(hinfo->tree).parameter_dcls; curitem; curitem = IDL_LIST(curitem).next) {
    hinfo->tree = IDL_LIST(curitem).data;
    orbit_cbe_hdr_process_piece(hinfo);
  }

  if(IDL_OP_DCL(op).context_expr)
    fprintf(hinfo->of, "CORBA_Context ctx, ");

  fprintf(hinfo->of, "CORBA_Environment *ev);\n");

  g_free(id);
  g_free(id2);
}

/* FIXME This function should check for redefined inherited ops, it doesnt
   currently - RHP */
static void
cbe_hdr_do_inherited_op_dcl(CBEHeaderInfo *hinfo, IDL_tree current_interface)
{
  char *id, *id2;
  IDL_tree ident, curitem, intf;

  if(!enable_inherited_ops)
    return;

  id = IDL_ns_ident_to_qstring(IDL_IDENT_TO_NS(IDL_INTERFACE(current_interface).ident), "_", 0);
  intf = IDL_get_parent_node(hinfo->tree, IDLN_INTERFACE, NULL);
  id2 = IDL_ns_ident_to_qstring(IDL_IDENT_TO_NS(IDL_INTERFACE(intf).ident),
				"_", 0);

  fprintf(hinfo->of, "extern ");

  orbit_cbe_write_typespec(hinfo->of, IDL_OP_DCL(hinfo->tree).op_type_spec);
  orbit_cbe_param_printptrs(hinfo->of, IDL_OP_DCL(hinfo->tree).op_type_spec, DATA_RETURN);

  ident = IDL_OP_DCL(hinfo->tree).ident;
  g_assert(ident);

  fprintf(hinfo->of, " %s_%s(%s _obj, ",
	  id, IDL_IDENT(ident).str, id);
  g_free(id);
  g_free(id2);

  for(curitem = IDL_OP_DCL(hinfo->tree).parameter_dcls; curitem; curitem = IDL_LIST(curitem).next) {
    hinfo->tree = IDL_LIST(curitem).data;

    /* I dont think anything below here needs to know about inheritance - RHP */
    orbit_cbe_hdr_process_piece(hinfo);
  }

  if(IDL_OP_DCL(hinfo->tree).context_expr)
    fprintf(hinfo->of, "CORBA_Context ctx, ");

  fprintf(hinfo->of, "CORBA_Environment *ev);\n");
}

static void
cbe_hdr_do_param_dcl(CBEHeaderInfo *hinfo)
{
  IDL_ParamRole r = DATA_IN;

  if(IDL_PARAM_DCL(hinfo->tree).attr == IDL_PARAM_IN)
    fprintf(hinfo->of, "const ");

  orbit_cbe_write_typespec(hinfo->of,
			   IDL_PARAM_DCL(hinfo->tree).param_type_spec);

  switch(IDL_PARAM_DCL(hinfo->tree).attr) {
  case IDL_PARAM_IN: r = DATA_IN; break;
  case IDL_PARAM_INOUT: r = DATA_INOUT; break;
  case IDL_PARAM_OUT: r = DATA_OUT; break;
  default:
    g_error("Unknown IDL_PARAM type");
  }

  orbit_cbe_param_printptrs(hinfo->of,
			    IDL_PARAM_DCL(hinfo->tree).param_type_spec, r);
  fprintf(hinfo->of, " %s, ", IDL_IDENT(IDL_PARAM_DCL(hinfo->tree).simple_declarator).str);
}

static void
cbe_hdr_do_forward_dcl(CBEHeaderInfo *hinfo)
{
  char *id;

  id = IDL_ns_ident_to_qstring(IDL_IDENT_TO_NS(IDL_INTERFACE(hinfo->tree).ident), "_", 0);

  fprintf(hinfo->of, "/* Begin forward declaration %s */\n\n", id);

  fprintf(hinfo->of, "  /* client-side data structures and methods */\n");
  fprintf(hinfo->of, "#ifndef _%s_defined\n"
		     "#define _%s_defined\n\n", id, id);
  fprintf(hinfo->of, "typedef CORBA_Object %s;\n", id);
  fprintf(hinfo->of, "#define %s__free CORBA_Object__free\n", id);
  fprintf(hinfo->of, "#endif /* !_%s_defined */\n\n", id);

  fprintf(hinfo->of, "/* End forward declaration %s */\n\n", id);

  g_free(id);
}

static void
cbe_hdr_do_type_integer(CBEHeaderInfo *hinfo)
{
  fprintf(hinfo->of, "CORBA_");

  if(!IDL_TYPE_INTEGER(hinfo->tree).f_signed)
    fprintf(hinfo->of, "unsigned_");

  switch(IDL_TYPE_INTEGER(hinfo->tree).f_type) {
  case IDL_INTEGER_TYPE_SHORT:
    fprintf(hinfo->of, "short");
    break;
  case IDL_INTEGER_TYPE_LONGLONG:
    fprintf(hinfo->of, "long_");
  case IDL_INTEGER_TYPE_LONG:
    fprintf(hinfo->of, "long");
    break;
  }
}

static void
cbe_hdr_do_type_float(CBEHeaderInfo *hinfo)
{
  switch(IDL_TYPE_FLOAT(hinfo->tree).f_type) {
  case IDL_FLOAT_TYPE_FLOAT:
    fprintf(hinfo->of, "CORBA_float");
    break;
  case IDL_FLOAT_TYPE_DOUBLE:
    fprintf(hinfo->of, "CORBA_double");
    break;
  case IDL_FLOAT_TYPE_LONGDOUBLE:
    fprintf(hinfo->of, "CORBA_long_double");
    break;
  }
}

static void
cbe_hdr_do_type_fixed(CBEHeaderInfo *hinfo)
{
  fprintf(hinfo->of, "CORBA_fixed_d_s");
}

static void
cbe_hdr_do_type_char(CBEHeaderInfo *hinfo)
{
  fprintf(hinfo->of, "CORBA_wchar");
}

static void
cbe_hdr_do_type_wide_char(CBEHeaderInfo *hinfo)
{
  fprintf(hinfo->of, "CORBA_wchar");
}

static void
cbe_hdr_do_type_string(CBEHeaderInfo *hinfo)
{
  fprintf(hinfo->of, "CORBA_char*");
}

static void
cbe_hdr_do_type_wide_string(CBEHeaderInfo *hinfo)
{
  fprintf(hinfo->of, "CORBA_wchar*");
}

static void
cbe_hdr_do_type_boolean(CBEHeaderInfo *hinfo)
{
  fprintf(hinfo->of, "CORBA_boolean");
}

static void
cbe_hdr_do_type_octet(CBEHeaderInfo *hinfo)
{
  fprintf(hinfo->of, "CORBA_octet");
}

static void
cbe_hdr_do_type_any(CBEHeaderInfo *hinfo)
{
  fprintf(hinfo->of, "CORBA_any");
}

static void
cbe_hdr_do_type_object(CBEHeaderInfo *hinfo)
{
  fprintf(hinfo->of, "CORBA_Object");
}

static void
cbe_hdr_do_type_typecode(CBEHeaderInfo *hinfo)
{
  fprintf(hinfo->of, "CORBA_TypeCode");
}

static void
cbe_hdr_do_type_enum(CBEHeaderInfo *hinfo)
{
  IDL_tree curitem;
  char *id, *enumid;

  /* CORBA spec says to do
	   typedef unsigned int enum_name;
     and then #defines for each enumerator.
     This works just as well and seems cleaner.
  */

  enumid = IDL_ns_ident_to_qstring(IDL_IDENT_TO_NS(IDL_TYPE_ENUM(hinfo->tree).ident), "_", 0);
  fprintf(hinfo->of, "#ifndef _%s_defined\n"
		     "#define _%s_defined\n\n", enumid, enumid);
  fprintf(hinfo->of, "typedef enum {\n");

  for(curitem = IDL_TYPE_ENUM(hinfo->tree).enumerator_list;
      curitem;
      curitem = IDL_LIST(curitem).next) {
    id = IDL_ns_ident_to_qstring(IDL_IDENT_TO_NS(IDL_LIST(curitem).data), "_", 0);

    fprintf(hinfo->of, "  %s%s\n",
	    id,
	    IDL_LIST(curitem).next?",":"");

    g_free(id);
  }

  fprintf(hinfo->of, "} %s;\n", enumid);
  fprintf(hinfo->of, "#endif /* !_%s_defined */\n\n", enumid);
  fprintf(hinfo->of, "extern const struct CORBA_TypeCode_struct TC_%s_struct;\n", enumid);
  fprintf(hinfo->of, "#define TC_%s (&TC_%s_struct)\n", enumid, enumid);

  g_free(enumid);
}

static void
cbe_hdr_do_type_sequence(CBEHeaderInfo *hinfo)
{
  fprintf(hinfo->of, "struct {\n");
  fprintf(hinfo->of, "  CORBA_unsigned_long _maximum;\n");
  fprintf(hinfo->of, "  CORBA_unsigned_long _length;\n");
  fprintf(hinfo->of, "  ");
  orbit_cbe_write_typespec(hinfo->of, IDL_TYPE_SEQUENCE(hinfo->tree).simple_type_spec);
  fprintf(hinfo->of, "* _buffer;\n");
  fprintf(hinfo->of, "  CORBA_boolean _release : 1; /* ORBit-specific; see page 19-14 of CORBA 2.2 spec */\n");
  fprintf(hinfo->of, "}");
}

static void
cbe_hdr_do_type_array(CBEHeaderInfo *hinfo)
{
  char *id;
  IDL_tree curitem;

  id = IDL_ns_ident_to_qstring(IDL_IDENT_TO_NS(IDL_TYPE_ARRAY(hinfo->tree).ident), "_", 0);

  fprintf(hinfo->of, " %s_slice", id);
  g_assert(IDL_TYPE_ARRAY(hinfo->tree).size_list);
  for(curitem = IDL_LIST(IDL_TYPE_ARRAY(hinfo->tree).size_list).next;
      curitem; curitem = IDL_LIST(curitem).next) {
    fprintf(hinfo->of, "[%qd]", IDL_INTEGER(IDL_LIST(curitem).data).value);
  }
  fprintf(hinfo->of, ";\n");
  fprintf(hinfo->of, "typedef %s_slice %s[%qd];\n", id, id,
	  IDL_INTEGER(IDL_LIST(IDL_TYPE_ARRAY(hinfo->tree).size_list).data).value);

  /* The ifdef corresponding to this was written in cbe_hdr_do_type_dcl */
  fprintf(hinfo->of, "#endif /* !_%s_defined */\n\n", id);
  fprintf(hinfo->of, "extern const struct CORBA_TypeCode_struct TC_%s_struct;\n", id);
  fprintf(hinfo->of, "#define TC_%s (&TC_%s_struct)\n", id, id);
  fprintf(hinfo->of, "extern %s_slice* %s__alloc(void);\n", id, id);
  fprintf(hinfo->of, "extern gpointer %s__free(gpointer mem, gpointer dat, CORBA_boolean free_strings); /* ORBit internals */\n", id);

  g_free(id);
}

static void
cbe_hdr_do_type_struct(CBEHeaderInfo *hinfo)
{
  char *id;
  IDL_tree curitem;
  CBEHeaderInfo child_hinfo = *hinfo;

  id = IDL_ns_ident_to_qstring(IDL_IDENT_TO_NS(IDL_TYPE_STRUCT(hinfo->tree).ident), "_", 0);
  fprintf(hinfo->of, "#ifndef _%s_defined\n"
		     "#define _%s_defined\n\n", id, id);
  fprintf(hinfo->of, "typedef struct %s {\n", id);

  if (IDL_TYPE_STRUCT(hinfo->tree).member_list) {
    for(curitem = IDL_TYPE_STRUCT(hinfo->tree).member_list; curitem;
        curitem = IDL_LIST(curitem).next) {
      child_hinfo.tree = IDL_LIST(curitem).data;
      orbit_cbe_hdr_process_piece(&child_hinfo);
      fprintf(hinfo->of, "\n");
    }
  } 
  else
    fprintf(hinfo->of, "	int empty_struct_member;\n");

  fprintf(hinfo->of, "} %s;\n", id);
  fprintf(hinfo->of, "#endif /* !_%s_defined */\n\n", id);
  fprintf(hinfo->of, "extern const struct CORBA_TypeCode_struct TC_%s_struct;\n", id);
  fprintf(hinfo->of, "#define TC_%s (&TC_%s_struct)\n", id, id);
  fprintf(hinfo->of, "extern %s* %s__alloc(void);\n", id, id);
  fprintf(hinfo->of, "extern gpointer %s__free(gpointer mem, gpointer dat, CORBA_boolean free_strings);\n", id);
  g_free(id);
}

static void
cbe_hdr_do_type_union(CBEHeaderInfo *hinfo)
{
  /*
    union Foo2 switch (char) {
    case 'a': long x;
    case 'b': short y;
    case 'c': char z; 
    };
  */

  char *id;
  IDL_tree curitem;
  CBEHeaderInfo child_hinfo = *hinfo;

  id = IDL_ns_ident_to_qstring(IDL_IDENT_TO_NS(IDL_TYPE_UNION(hinfo->tree).ident), "_", 0);

  fprintf(hinfo->of, "#ifndef _%s_defined\n"
		     "#define _%s_defined\n\n", id, id);
  fprintf(hinfo->of, "typedef struct {\n  ");
  orbit_cbe_write_typespec(hinfo->of, IDL_TYPE_UNION(hinfo->tree).switch_type_spec);

  fprintf(hinfo->of, " _d;\n  union {\n");

  for(curitem = IDL_TYPE_UNION(hinfo->tree).switch_body; curitem; curitem = IDL_LIST(curitem).next) {
    fprintf(hinfo->of, "    ");
    child_hinfo.tree = IDL_LIST(curitem).data;
    orbit_cbe_hdr_process_piece(&child_hinfo);
  }

  fprintf(hinfo->of, "  } _u;\n} %s;\n", id);
  fprintf(hinfo->of, "#endif /* !_%s_defined */\n\n", id);
  fprintf(hinfo->of, "extern const struct CORBA_TypeCode_struct TC_%s_struct;\n", id);
  fprintf(hinfo->of, "#define TC_%s (&TC_%s_struct)\n", id, id);
  fprintf(hinfo->of, "extern %s* %s__alloc(void);\n", id, id);
  fprintf(hinfo->of, "extern gpointer %s__free(gpointer mem, gpointer dat, CORBA_boolean free_strings); /* ORBit internals */\n", id);

  g_free(id);
}


static void
cbe_hdr_do_member(CBEHeaderInfo *hinfo)
{
  IDL_tree curitem, li, sz;
  fprintf(hinfo->of, "  ");

  for(curitem = IDL_MEMBER(hinfo->tree).dcls; curitem; curitem = IDL_LIST(curitem).next) {
    orbit_cbe_write_typespec(hinfo->of, IDL_MEMBER(hinfo->tree).type_spec);
    li = IDL_LIST(curitem).data;
    switch(IDL_NODE_TYPE(li)) {
    case IDLN_TYPE_ARRAY:
      fprintf(hinfo->of, " %s",
	      IDL_IDENT(IDL_TYPE_ARRAY(li).ident).str);
      for(sz = IDL_TYPE_ARRAY(li).size_list; sz; sz = IDL_LIST(sz).next) {
	fprintf(hinfo->of, "[%" IDL_LL "d]", IDL_INTEGER(IDL_LIST(sz).data).value);
      }
      fprintf(hinfo->of, ";\n");
      break;
    case IDLN_IDENT:
      fprintf(hinfo->of, " %s;\n",
	      IDL_IDENT(li).str);
      break;
    default:
      g_error("We were asked to print a member for a %s", IDL_tree_type_names[IDL_NODE_TYPE(li)]);
    }
  }
}

static void
cbe_hdr_do_case_stmt(CBEHeaderInfo *hinfo)
{
  IDL_tree curitem;
  CBEHeaderInfo child_hinfo = *hinfo;

  child_hinfo.tree = IDL_CASE_STMT(hinfo->tree).element_spec;
  orbit_cbe_hdr_process_piece(&child_hinfo);

  fprintf(hinfo->of, "  /* switch value%s ",
	  IDL_LIST(IDL_CASE_STMT(hinfo->tree).labels).next?"s":"");
  for(curitem = IDL_CASE_STMT(hinfo->tree).labels;
      curitem;
      curitem = IDL_LIST(curitem).next) {
    if(IDL_LIST(curitem).data)
      orbit_cbe_write_const(hinfo->of, IDL_LIST(curitem).data);
    else
      fprintf(hinfo->of, "default");
    if (IDL_LIST(curitem).next)
      fprintf(hinfo->of, ", ");
  }
  fprintf(hinfo->of, " */\n");
}

static void
cbe_hdr_interface_print_epv_for_op(CBEHeaderInfo *hinfo)
{
  /* hacked from cbe_hdr_do_op_dcl() */
  IDL_tree curitem;
  

  fprintf(hinfo->of, "  ");
  orbit_cbe_write_typespec(hinfo->of, IDL_OP_DCL(hinfo->tree).op_type_spec);
  orbit_cbe_param_printptrs(hinfo->of, IDL_OP_DCL(hinfo->tree).op_type_spec, DATA_RETURN);

  fprintf(hinfo->of, " (*%s)(PortableServer_Servant servant, ",
	  IDL_IDENT(IDL_OP_DCL(hinfo->tree).ident).str);

  /* op = hinfo->tree; */
  for(curitem = IDL_OP_DCL(hinfo->tree).parameter_dcls; curitem; curitem = IDL_LIST(curitem).next) {
    hinfo->tree = IDL_LIST(curitem).data;
    orbit_cbe_hdr_process_piece(hinfo);
  }

#if 0
  /* hinfo->tree.. see op saved above here... */
  /* I'm unsure of how CORBA_Context should be used here... */
  if(IDL_OP_DCL(hinfo->tree).context_expr)
    fprintf(hinfo->of, "CORBA_Context ctx, ");
#endif

  fprintf(hinfo->of, "CORBA_Environment *ev);\n");
}

static void
cbe_hdr_interface_print_epv_for_attr(CBEHeaderInfo *hinfo)
{
  /* hacked from above routine */
  IDL_tree curitem;

  for(curitem = IDL_ATTR_DCL(hinfo->tree).simple_declarations;
      curitem; curitem = IDL_LIST(curitem).next) {
    fprintf(hinfo->of, "  ");
    orbit_cbe_write_typespec(hinfo->of,
			     IDL_ATTR_DCL(hinfo->tree).param_type_spec);
    orbit_cbe_param_printptrs(hinfo->of,
			      IDL_ATTR_DCL(hinfo->tree).param_type_spec,
			      DATA_RETURN);

    fprintf(hinfo->of,
	    " (*_get_%s)(PortableServer_Servant servant, CORBA_Environment *ev);\n",
	    IDL_IDENT(IDL_LIST(curitem).data).str);

    if(!IDL_ATTR_DCL(hinfo->tree).f_readonly) {
      fprintf(hinfo->of, "  void (*_set_%s)(PortableServer_Servant servant, const ",
	      IDL_IDENT(IDL_LIST(curitem).data).str);
      
      orbit_cbe_write_typespec(hinfo->of,
			       IDL_ATTR_DCL(hinfo->tree).param_type_spec);
      orbit_cbe_param_printptrs(hinfo->of,
				IDL_ATTR_DCL(hinfo->tree).param_type_spec,
				DATA_IN);
      fprintf(hinfo->of, " value, CORBA_Environment *ev);\n");
    }
  }
}

static void
cbe_hdr_interface_print_epv(CBEHeaderInfo *hinfo)
{
  CBEHeaderInfo subhinfo = *hinfo;
  IDL_tree curitem;

  g_assert(IDL_NODE_TYPE(hinfo->tree) == IDLN_INTERFACE);

  for(curitem = IDL_INTERFACE(hinfo->tree).body;
      curitem; curitem = IDL_LIST(curitem).next) {

    subhinfo.tree = IDL_LIST(curitem).data;

    switch(IDL_NODE_TYPE(IDL_LIST(curitem).data)) {
    case IDLN_OP_DCL:
      cbe_hdr_interface_print_epv_for_op(&subhinfo);
      break;
    case IDLN_ATTR_DCL:
      cbe_hdr_interface_print_epv_for_attr(&subhinfo);
      break;
    default:
      break;
    }
  }
}

static void
cbe_hdr_interface_print_vepv(IDL_tree node, FILE *of)
{
  char *id = IDL_ns_ident_to_qstring(IDL_IDENT_TO_NS(IDL_INTERFACE(node).ident),
				     "_", 0);
  fprintf(of, "  POA_%s__epv *%s_epv;\n", id, id);
  g_free(id);
}

static void
cbe_hdr_interface_print_inheritance_ops(IDL_tree node, CBEHeaderInfo *current)
{
  CBEHeaderInfo subhinfo = *current;
  IDL_tree curitem;
  char *id;

  g_assert(current->tree);
  g_assert(IDL_NODE_TYPE(node) == IDLN_INTERFACE);

  if(node==current->tree) {
    /* We don't inherit from ourself... */
    return;
  }

  id = IDL_ns_ident_to_qstring(IDL_IDENT_TO_NS(IDL_INTERFACE(node).ident), "_", 0);
  fprintf(current->of, "/* From interface %s */\n", id);
  g_free(id);

  /* Print the operations defined for this interface, but in current's
     namespace */

  for(curitem = IDL_INTERFACE(node).body;
      curitem; curitem = IDL_LIST(curitem).next) {

    subhinfo.tree = IDL_LIST(curitem).data;

    switch(IDL_NODE_TYPE(IDL_LIST(curitem).data)) {
    case IDLN_OP_DCL:
      cbe_hdr_do_inherited_op_dcl(&subhinfo, current->tree);
      break;
    case IDLN_ATTR_DCL:
      cbe_hdr_do_inherited_attr_dcl(&subhinfo, current->tree);
      break;
    default:
      break;
    }
  }
}

static void
cbe_hdr_do_interface(CBEHeaderInfo *hinfo)
{
  char *id;
  CBEHeaderInfo subhinfo = *hinfo;

  id = IDL_ns_ident_to_qstring(IDL_IDENT_TO_NS(IDL_INTERFACE(hinfo->tree).ident), "_", 0);

  fprintf(hinfo->of, "/* Begin interface %s */\n\n", id);

  fprintf(hinfo->of, "  /* client-side data structures and methods */\n");
  fprintf(hinfo->of, "#ifndef _%s_defined\n"
		     "#define _%s_defined\n\n", id, id);
  fprintf(hinfo->of, "typedef CORBA_Object %s;\n", id);
  fprintf(hinfo->of, "#define %s__free CORBA_Object__free\n", id);
  fprintf(hinfo->of, "#endif /* !_%s_defined */\n\n", id);
  fprintf(hinfo->of, "extern CORBA_unsigned_long %s__classid;\n", id);
  fprintf(hinfo->of, "extern const struct CORBA_TypeCode_struct TC_%s_struct;\n",
	  id);
  fprintf(hinfo->of, "#define TC_%s (&TC_%s_struct)\n", id, id);
  subhinfo.tree = IDL_INTERFACE(hinfo->tree).body;
  cbe_hdr_do_list(&subhinfo);

  if(IDL_INTERFACE(hinfo->tree).inheritance_spec != NULL) {
    fprintf(hinfo->of, "/* Begin inherited operations for %s */\n\n", id);
    subhinfo.tree = IDL_INTERFACE(hinfo->tree).inheritance_spec;
    IDL_tree_traverse_parents(subhinfo.tree, (gpointer)cbe_hdr_interface_print_inheritance_ops, hinfo);
    fprintf(hinfo->of, "/* End inherited operations for %s */\n\n", id);
  }

  fprintf(hinfo->of, "  /* server-side (via the POA) data structures and methods */\n");
  fprintf(hinfo->of, "#ifndef _POA_%s__epv_defined\n"
		     "#define _POA_%s__epv_defined\n\n", id, id);
  fprintf(hinfo->of, "typedef struct {\n");
  fprintf(hinfo->of, "  void *_private;\n");
  cbe_hdr_interface_print_epv(hinfo);
  fprintf(hinfo->of, "} POA_%s__epv;\n", id);
  fprintf(hinfo->of, "#endif /* !_POA_%s__epv_defined */\n\n", id);

  fprintf(hinfo->of, "#ifndef _POA_%s__vepv_defined\n"
		     "#define _POA_%s__vepv_defined\n\n", id, id);
  fprintf(hinfo->of, "typedef struct {\n");
  fprintf(hinfo->of, "  PortableServer_ServantBase__epv* _base_epv;\n");
  IDL_tree_traverse_parents(hinfo->tree, (gpointer)cbe_hdr_interface_print_vepv, hinfo->of);
  fprintf(hinfo->of, "} POA_%s__vepv;\n", id);
  fprintf(hinfo->of, "#endif /* !_POA_%s__vepv_defined */\n\n", id);

  fprintf(hinfo->of, "#ifndef _POA_%s_defined\n"
		     "#define _POA_%s_defined\n\n", id, id);
  fprintf(hinfo->of, "typedef struct {\n");
  fprintf(hinfo->of, "  void * _private;\n");
  fprintf(hinfo->of, "  POA_%s__vepv* vepv;\n", id);
  fprintf(hinfo->of, "} POA_%s;\n", id);
  fprintf(hinfo->of, "#endif /* !_POA_%s_defined */\n\n", id);

  fprintf(hinfo->of,
	  "extern void POA_%s__init(POA_%s *servant, CORBA_Environment *ev);\n", id, id);
  fprintf(hinfo->of,
	  "extern void POA_%s__fini(POA_%s *servant, CORBA_Environment *ev);\n", id, id);

  fprintf(hinfo->of, "/* End interface %s */\n", id);
    
  g_free(id);
}

static void
cbe_hdr_do_binop(CBEHeaderInfo *hinfo)
{
  g_assert(!"Not yet implemented");
}

static void
cbe_hdr_do_unaryop(CBEHeaderInfo *hinfo)
{
  g_assert(!"Not yet implemented");
}

static void
cbe_hdr_do_native(CBEHeaderInfo *hinfo)
{
  char *id;

  id = IDL_ns_ident_to_qstring(IDL_IDENT_TO_NS(IDL_NATIVE(hinfo->tree).ident),
			       "_", 0);  
  fprintf(hinfo->of, "typedef void *%s;\n", id);

  g_free(id);
}
