/*
 * Copyright (c) 1995, 1996, 1997, 1998, 1999 The University of Utah and
 * the Computer Systems Laboratory at the University of Utah (CSL).
 *
 * This file is part of Flick, the Flexible IDL Compiler Kit.
 *
 * Flick is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * Flick is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Flick; see the file COPYING.  If not, write to
 * the Free Software Foundation, 59 Temple Place #330, Boston, MA 02111, USA.
 */

#include <stdio.h>
/*
  #include <string.h>
  We declare these individually rather than use the header because
  the HPUX and SunOS4 systems we tried compiling on have funky g++
  installations that make strrchr get munged _strrchr__FPci instead
  of _strrchr
  */
extern "C" char *strrchr(const char *s, int c);
extern "C" int strcmp(const char *s, const char *s2);

#include <mom/compiler.h>
#include <mom/libaoi.h>
#include <mom/c/pfe.hh>
#include <mom/c/libcast.h>
#include <mom/c/libpres_c.h>

#include "private.hh"

/* Generate presentation for an AOI interface definition. */
void pg_state::p_interface_def(aoi_interface *ai)
{
	/*
	 * This function generates `pres_c_stub' entries for the given AOI
	 * interface `a'.  These `pres_c_stub' entries will be elements in the
	 * `out_pres->stubs' member variable in the `pg_state' structure.  For
	 * each AOI interface there will be one server stub (i.e., the server
	 * dispatch function) but multiple client stubs (generally, one client
	 * stub for each function).
	 *
	 * Filling in the `pres_c_stub' entry will involve allocation and
	 * assignment of other CAST and PRES_C data structures.
	 */
	
	/* Generate an `#include' for this interface if necessary. */
	p_interface_def_include(ai);
	
	/* Generate a typedef for the object reference (interface name). */
	p_interface_def_typedef(ai);
	
	/* Generate the contents of this interface. */
	gen_scope(a(cur_aoi_idx).scope + 1);
	
	if (gen_client)	{
		/* Generate client stubs. */
		p_client_stubs(ai);
	}
	if (gen_server)	{
		/* Generate the server skeleton stub. */
		p_skel(ai);
	}
}


/*****************************************************************************/

/***** Auxiliary functions. *****/

/*
 * Generate an `#include' statement to get user-supplied goo for the current
 * interface.  Most presentations don't require this.  This method is
 * sufficiently generic (customizable though the `calc_name' methods and format
 * strings) that few if any PGs should need to override this.
 *
 * XXX --- This code is similar to that in `pg_state::build_init_cast'.  Maybe
 * we should write a generic `#include' statement verifier.
 */
void pg_state::p_interface_def_include(aoi_interface * /*interface*/)
{
	char *include_file_name;
	char *include_file_name_nondir;
	
	calc_name_component *separator_component;
	char separator_char;
	
	/*
	 * Compute the `#include' file name to get interface-specific goo.
	 */
	include_file_name =
		calc_interface_include_file_name(a(cur_aoi_idx).name);
	
	/*
	 * Now we have to make sure that the file name is valid.  Dig the
	 * file name component separator character out of our `names.literals'.
	 */
	separator_component =
		&(names.literals[name_strings::
				filename_component_separator_lit]);
	
	switch (separator_component->len) {
	case 1:
		separator_char = *(separator_component->str);
		break;
		
	case 0:
		warn("Can't really cope with a zero-character filename "
		     "component separator.");
		separator_char = '/';
		break;
		
	default:
		warn("Can't really cope with a multicharacter filename "
		     "component separator.");
		separator_char = separator_component->
				 str[separator_component->len - 1];
		break;
	}
	
	/*
	 * Now find the final file name component.
	 */
	include_file_name_nondir = strrchr(include_file_name, separator_char);
	if (include_file_name_nondir) {
		/*
		 * Don't increment in the bizarro case that `separator_char'
		 * is NUL.
		 */
		if (*include_file_name_nondir)
			++include_file_name_nondir;
	} else
		include_file_name_nondir = include_file_name;
	
	/*
	 * If the `#include' file name is bogus, try the default instead.
	 */
	if ((strcmp("", include_file_name_nondir) == 0)
	    || (strcmp(".h", include_file_name_nondir) == 0)) {
		/* Redo `include_file_name' and `include_file_name_nondir'. */
		include_file_name =
			calc_interface_default_include_file_name(
				a(cur_aoi_idx).name);
		
		include_file_name_nondir = strrchr(include_file_name,
						   separator_char);
		if (include_file_name_nondir) {
			if (*include_file_name_nondir)
				++include_file_name_nondir;
		} else
			include_file_name_nondir = include_file_name;
	}
	
	/*
	 * If the `#include' file name is good, emit the `#include' statement.
	 */
	if ((strcmp("", include_file_name_nondir) != 0)
	    && (strcmp(".h", include_file_name_nondir) != 0))
		p_emit_include_stmt(include_file_name,
				    1 /* 1 == system header */);
}

/*
 * Generate a `typedef' for the interface-specific object reference (derived
 * from the interface name).  Some presentation generators may override this
 * method, but again, the preferred specialization technique is through the
 * `calc_name' facilities (i.e., changing the format strings).
 */
void pg_state::p_interface_def_typedef(aoi_interface *ai)
{
	char *interface_name = a(cur_aoi_idx).name;
	cast_scoped_name basic_object_type_name;
	char *object_type_name;
	aoi_ref parent_ref;
	int cdef;
	
	/*
	 * Compute the name of the ``basic'' object type: the object reference
	 * type provided by the runtime (outside of Flick) that will be used to
	 * define our interface-specific object type.  For example, in CORBA,
	 * all object references are defined in terms of `CORBA_Object'.
	 *
	 * Also, compute the name of the interface-specific object type.
	 */
	parent_ref = aoi_get_parent_scope(in_aoi, cur_aoi_idx);
	if (gen_client) {
		basic_object_type_name =
			calc_client_basic_object_type_scoped_name(
				parent_ref, interface_name);
		object_type_name =
			calc_client_interface_object_type_name(interface_name);
		
	} else if (gen_server) {
		basic_object_type_name =
			calc_server_basic_object_type_scoped_name(
				parent_ref, interface_name);
		object_type_name =
			calc_server_interface_object_type_name(interface_name);
		
	} else
		panic("In `pg_state::p_interface_def_typedef', "
		      "generating neither client nor server.");
	
	/*
	 * Now make our typedef.
	 */
	cdef = cast_add_def((cast_scope *)top_ptr(scope_stack),
			    cast_new_scoped_name(object_type_name, NULL),
			    CAST_SC_NONE,
			    CAST_TYPEDEF,
			    ch(cur_aoi_idx, PG_CHANNEL_CLIENT_DECL),
			    CAST_PROT_NONE);
	c(cdef).u.cast_def_u_u.typedef_type =
		cast_new_type_scoped_name(basic_object_type_name);
	
	if (async_stubs)
		p_interface_async_msg_types(ai);
}

/*
 * If you override this method, you should also override `p_forward_type',
 * which handles forward interface declarations.
 */
void pg_state::p_interface_type(aoi_interface * /*ai*/,
				p_type_collection **out_ptc)
{
	/*
	 * Here we are handling *basic* interface types, not *typedef'ed*
	 * interface types.  This method is called by `p_type' when we have a
	 * direct reference to an AOI interface.  References to *specific*
	 * interface types always occur through AOI_INDIRECT nodes, and so we
	 * handle those cases in `p_indirect_type'.
	 */
	p_type_collection *ptc;
	pres_c_mapping map;
	p_type_node *ptn;
	cast_type ctype;

	ptc = p_new_type_collection(a(cur_aoi_idx).name);
	ptn = new p_type_node;
	ptn->set_name("definition");
	ptn->set_format("%s");
	map = pres_c_new_mapping(PRES_C_MAPPING_REFERENCE);
	map->pres_c_mapping_u_u.ref.ref_count = 1;
	map->pres_c_mapping_u_u.ref.arglist_name = ir_strlit("");
	
	if (gen_client) {
		/* default for client is sending copies */
		map->pres_c_mapping_u_u.ref.kind
			= PRES_C_REFERENCE_COPY;
		ctype =
			cast_new_type_name(
				calc_client_basic_object_type_name(
					a(cur_aoi_idx).name /* XXX ? */
					));
	} else if (gen_server) {
		/* default for server is returning its only copy */
		map->pres_c_mapping_u_u.ref.kind = PRES_C_REFERENCE_MOVE;
		ctype = cast_new_type_name(
				calc_server_basic_object_type_name(
					a(cur_aoi_idx).name /* XXX ? */
					));
	}
	else
		panic("In `pg_state::p_interface_type', "
		      "generating neither client nor server.");
	ptn->set_type(ctype);
	ptn->set_mapping(map);
	ptc->add_type("default", ptn);
	
	if( *out_ptc )
		(*out_ptc)->set_collection_ref(ptc);
	else
		*out_ptc = ptc;
}

void pg_state::p_interface_async_msg_types(aoi_interface * /*ai*/)
{
	char *interface_name = a(cur_aoi_idx).name;
	char *interface_type_name
		= calc_basic_message_type_name(interface_name);
	int cdef;
	
	cdef = cast_add_def(
		(cast_scope *)top_ptr(scope_stack),
		cast_new_scoped_name(calc_interface_message_request_type_name(
			interface_name), NULL),
		CAST_SC_NONE,
		CAST_TYPEDEF,
		ch(cur_aoi_idx, PG_CHANNEL_CLIENT_DECL),
		CAST_PROT_NONE);
	c(cdef).u.cast_def_u_u.typedef_type =
		cast_new_type_name(interface_type_name);
	
	cdef = cast_add_def(
		(cast_scope *)top_ptr(scope_stack),
		cast_new_scoped_name(calc_interface_message_reply_type_name(
			interface_name), NULL),
		CAST_SC_NONE,
		CAST_TYPEDEF,
		ch(cur_aoi_idx, PG_CHANNEL_CLIENT_DECL),
		CAST_PROT_NONE);
	c(cdef).u.cast_def_u_u.typedef_type =
		cast_new_type_name(interface_type_name);
}

/* End of file. */


syntax highlighted by Code2HTML, v. 0.9.1