// **********************************************************************
//
// Copyright (c) 1999
// Object Oriented Concepts, Inc.
// Billerica, MA, USA
//
// All Rights Reserved
//
// **********************************************************************

#include <OB/CORBA.h>
#include <Types.h>
#include <Util.h>
#include <GenUtil.h>
#include <GenCPP.h>

// ----------------------------------------------------------------------
// Generate code for the source file, general part
// ----------------------------------------------------------------------

void
IdlCPPGenerator::genCPlusPlusC(CORBA_Container_ptr container,
			       IdlPrettyPrint& out)
{
    //
    // Get scope and prefix
    // (prefix needed if alternative module mapping is used)
    //
    CORBA_String_var scope;
    CORBA_String_var pre;
    getScopeAndPrefix(container, scope.out(), pre.out());

    //
    // Get container contents descriptions
    //
    CORBA_Container::DescriptionSeq_var seq =
	container -> describe_contents(CORBA_dk_all, true, -1);

    CORBA_ULong i, j;

    for(i = 0 ; i < seq -> length() ; i++)
    {
	switch(seq[i].kind)
	{
	case CORBA_dk_Constant:
	{
	    //
	    // Constant
	    //
	    CORBA_ConstantDescription* desc;
	    CORBA_Boolean b = seq[i].value >>= desc;
	    assert(b);

	    if(!check(desc -> id))
		continue;

	    CORBA_Identifier_var name = fixKwd(desc -> name);
	    CORBA_ScopedName_var absolute = getAbsolute(desc -> id);

	    comment(desc -> id, out);
	    
	    CORBA_String_var s = getTypeString("", desc -> type,
					       GetTypeConst,
					       false, absolute);

	    out.sep();
	    out << '\n' << s << " = ";

	    CORBA_TypeCode_var tc = desc -> value.type();
	    tc = OBGetOrigType(tc);

	    switch(tc -> kind())
	    {
	    case CORBA_tk_short:
	    {
		CORBA_Short v;
		CORBA_Boolean b = desc -> value >>= v;
		assert(b);
		out << v;
		break;
	    }

	    case CORBA_tk_ushort:
	    {
		CORBA_UShort v;
		CORBA_Boolean b = desc -> value >>= v;
		assert(b);
		out << v;
		break;
	    }

	    case CORBA_tk_long:
	    {
		CORBA_Long v;
		CORBA_Boolean b = desc -> value >>= v;
		assert(b);
		out << v;
		break;
	    }

	    case CORBA_tk_ulong:
	    {
		CORBA_ULong v;
		CORBA_Boolean b = desc -> value >>= v;
		assert(b);
		out << v;
		break;
	    }

	    case CORBA_tk_float:
	    {
		CORBA_Float v;
		CORBA_Boolean b = desc -> value >>= v;
		assert(b);
		out << v;
		break;
	    }

	    case CORBA_tk_double:
	    {
		CORBA_Double v;
		CORBA_Boolean b = desc -> value >>= v;
		assert(b);
		out << v;
		break;
	    }

	    case CORBA_tk_string:
	    {
		char* v;
		CORBA_ULong l = tc -> length();
		CORBA_Any::to_string to(v, l);
		CORBA_Boolean b = desc -> value >>= to;
		assert(b);
		CORBA_String_var s = CORBA_string_dup(v);
		IdlAddEscapes(s.inout(), true);
		out << s;
		break;
	    }

	    case CORBA_tk_char:
	    {
		CORBA_Char v;
		CORBA_Boolean b = desc -> value >>= CORBA_Any::to_char(v);
		assert(b);
		CORBA_String_var s;
		if(v == '\0')
		    s = CORBA_string_dup("\\0");
		else
		{
		    s = CORBA_string_alloc(1);
		    s[0] = v;
		    s[1] = '\0';
		    IdlAddEscapes(s.inout(), false);
		}
		out << "(CORBA_Char)'" << s << "'";
		break;
	    }

	    case CORBA_tk_boolean:
	    {
		CORBA_Boolean v;
		CORBA_Boolean b = desc -> value >>= CORBA_Any::to_boolean(v);
		assert(b);
		out << (v ? "CORBA_TRUE" : "CORBA_FALSE");
		break;
	    }

	    default:
		assert(false);
		break;
	    }

	    out << ';';

	    break;
	}

	case CORBA_dk_Interface:
	{
	    //
	    // Interface
	    //
	    CORBA_InterfaceDescription* desc;
	    CORBA_Boolean b = seq[i].value >>= desc;
	    assert(b);

	    if(!check(desc -> id))
		continue;

	    CORBA_Identifier_var name = fixKwd(desc -> name);
	    CORBA_ScopedName_var absolute = getAbsolute(desc -> id);

	    comment(desc -> id, out);

	    //
	    // _var type
	    //
	    out.sep();
	    out.direct("\n#ifndef HAVE_NO_EXPLICIT_TEMPLATES");
	    out << "\ntemplate class OBObjVar< " << absolute << " >;";
	    out << "\ntemplate class OBObjForSeq< " << absolute << " >;";
	    out.direct("\n#else");
	    out.direct("\n#ifdef HAVE_PRAGMA_DEFINE");
	    out << "\n#pragma define(OBObjVar< " << absolute << " >)";
	    out << "\n#pragma define(OBObjForSeq< " << absolute << " >)";
	    out.direct("\n#endif"); // HAVE_PRAGMA_DEFINE
	    out.direct("\n#endif"); // HAVE_NO_EXPLICIT_TEMPLATES

	    //
	    // Constructor and destructor
	    //

	    /*
	     * Nothing to do here, constructor is defined inline,
	     * destructor is not needed
	     */
	    
	    //
	    // release, is_nil, _duplicate, _nil
	    //

	    /*
	     * Nothing to do here, all functions are defined inline
	     */

	    //
	    // OBDuplicate and OBRelease
	    //
	    out.sep();	    
    	    out << "\nvoid\nOBDuplicate(" << absolute << "_ptr p)";
	    out.start();
	    out << "\nif(p)";
	    out.inc();
	    out << "\np -> _OB_incRef();";
	    out.dec();
	    out.end();

	    out.sep();
    	    out << "\nvoid\nOBRelease(" << absolute << "_ptr p)";
	    out.start();
	    out << "\nif(p)";
	    out.inc();
	    out << "\np -> _OB_decRef();";
	    out.dec();
	    out.end();

/*
	    //
	    // _is_a
	    //
	    out.sep();
	    out << "\nCORBA_Boolean\n" << absolute
		<< "::_is_a(const char* _ob_id)";
	    out.start();
	    out << "\nassert_nca(_ob_id, OBNCANullString);";
	    out.sep();
	    out << "\nif(strcmp(\"" << desc -> id << "\", _ob_id) == 0)";
	    out.inc();
	    out << "\nreturn true;";
	    out.dec();
	    if(desc -> base_interfaces.length() == 0)
	    {
		out << "\nelse";
		out.inc();
		out << "\nreturn CORBA_Object::_is_a(_ob_id);";
		out.dec();
	    }
	    else
	    {
		for(j = 0 ; j < desc -> base_interfaces.length() ; j++)
		{
		    const char* id = desc -> base_interfaces[j];
		    CORBA_ScopedName_var baseAbsolute = getAbsolute(id);
		    out << "\nelse if(" << baseAbsolute << "::_is_a(_ob_id))";
		    out.inc();
		    out << "\nreturn true;";
		    out.dec();
		}
		out << "\nelse";
		out.inc();
		out << "\nreturn false;";
		out.dec();
	    }
	    out.end();
*/
	    //
	    // _narrow
	    //
	    out.sep();
	    out << '\n' << absolute << "_ptr\n" << absolute
		<< "::_narrow(CORBA_Object_ptr p)";
	    out.start();
	    out << "\nif(!CORBA_is_nil(p))";
	    out.start();
	    out << "\nvoid* v = p -> _OB_narrowHelp(\"" << desc -> id
		<< "\");";
	    out.sep();
	    out << "\nif(v)";
	    out.inc();
	    out << "\nreturn _duplicate((" << pre << name << "_ptr)v);";
	    out.dec();
	    if(!local_)
	    {
		out.sep();
		out << "\nif(p -> _OB_remoteIsA(\"" << desc -> id << "\"))";
		out.start();
		out << '\n' << pre << name << "_ptr val = new " << pre << name
		    << ';';
		out << "\nval -> _OB_copyFrom(p);";
		out << "\nreturn val;";
		out.end();
	    }
	    out.end();
	    out.sep();
	    out << "\nreturn _nil();";
	    out.end();

	    //
	    // _OB_narrowHelp
	    //
	    out.sep();
	    out << "\nvoid*\n" << absolute
		<< "::_OB_narrowHelp(const char* _ob_id) const";
	    out.start();
	    out << "\nif(strcmp(\"" << desc -> id << "\", _ob_id) == 0)";
	    out.inc();
	    out << "\nreturn (void*)this;";
	    out.dec();
	    out << "\nelse";

	    if(desc -> base_interfaces.length() == 0)
	    {
		out.inc();
		out << "\nreturn CORBA_Object::_OB_narrowHelp(_ob_id);";
		out.dec();
	    }
	    else
	    {
		out.start();
		out << "\nvoid* v;";

		for(j = 0 ; j < desc -> base_interfaces.length() ; j++)
		{
		    const char* id = desc -> base_interfaces[j];
		    CORBA_ScopedName_var baseAbsolute = getAbsolute(id);

		    out << "\nif((v = " << baseAbsolute
			<< "::_OB_narrowHelp(_ob_id)) != 0)";
		    out.inc();
		    out << "\nreturn v;";
		    out.dec();
		}
		out << "\nreturn 0;";
		out.end();
	    }
	    out.end();

	    //
	    // _OB_typeId
	    //
 	    out.sep();
 	    out << "\nconst char*\n" << absolute << "::_OB_typeId() const";
 	    out.start();
 	    out << "\nreturn \"" << desc -> id << "\";";
 	    out.end();

	    if(!local_)
	    {
		//
		// CDR functions
		//
		out.sep();
		out << "\nvoid\nOBUnmarshal(" << absolute
		    << "_ptr& val, const CORBA_Octet*& coct, bool swap)";
		out.start();
		// Don't release here! Old value must be released on exit
		// of this function
		out << '\n' << absolute << "_var old = val;";
		out << "\nCORBA_Object_var p;";
		out << "\nOBUnmarshal(p.inout(), coct, swap);";
		out.sep();
		out << "\nif(!CORBA_is_nil(p))";
		out.start();
		out << "\nvoid* v = p -> _OB_narrowHelp(\"" << desc -> id
		    << "\");";
		out.sep();
		out << "\nif(v)";
		out.inc();
		out << "\nval = " << absolute << "::_duplicate(("
		    << absolute << "_ptr)v);";
		out.dec();
		out << "\nelse";
		out.start();
		out << "\nassert_nca(!(p -> _is_local() && "
		    << "p -> _is_dynamic()), OBNCADynamicAsStatic);";
		out << "\nassert(!p -> _is_local());";
		out << "\nval = new " << absolute << ';';
		out << "\nval -> _OB_copyFrom(p);";
		out.end();
		out.end();
		out << "\nelse";
		out.inc();
		out << "\nval = " << absolute << "::_nil();";
		out.dec();
		out.end();
	    }

	    if(!noTC_)
	    {
		//
		// TypeCode constant
		//
		out.sep();
		out << "\nOBTypeCodeConst " << scope << pre
		    << "_tc_" << name << '(';
		
		CORBA_InterfaceDef_var interf =
		    CORBA_InterfaceDef::_narrow(seq[i].contained_object);
		CORBA_TypeCode_var type = interf -> type();
		IdlOutputAsciiTypeCode(type, out);
		out << ");";

		//
		// Any insertion and extraction
		//
		out.sep();
		out << "\nvoid\noperator<<=(CORBA_Any& any, " << absolute
		    << "_ptr val)";
		out.start();
		out << "\nOBObjAny* o = new OBObjAny;";
		out << "\no -> b = CORBA_Object::_duplicate(val);";
		out << "\no -> d = CORBA_Object::_duplicate(val);";
		out << "\nany.replace("
		    << scope << pre << "_tc_" << name << ", o, true);";
		out.end();

		out.sep();
		out << "\nvoid\noperator<<=(CORBA_Any& any, " << absolute
		    << "_ptr* val)";
		out.start();
		out << "\nOBObjAny* o = new OBObjAny;";
		out << "\no -> b = *val;";
		out << "\no -> d = CORBA_Object::_duplicate(*val);";
		out << "\nany.replace("
		    << scope << pre << "_tc_" << name << ", o, true);";
		out.end();

		out.sep();
		out << "\nCORBA_Boolean\noperator>>=(const CORBA_Any& any, "
		    << absolute << "_ptr& val)";
		out.start();
		out << "\nif(any.check_type("
		    << scope << pre << "_tc_" << name << "))";
		out.start();
		out << "\nOBObjAny* o = (OBObjAny*)any.value();";
		out << "\nassert(o);";
		out.sep();
		out << "\nif(!CORBA_is_nil(o -> d))";
		out.start();
		out << "\nvoid* v = o -> d -> _OB_narrowHelp(\""
		    << desc -> id << "\");";
		out.sep();
		out << "\nif(v)";
		out.inc();
		out << "\nval = (" << absolute << "_ptr)v;";
		out.dec();
		out << "\nelse";
		out.start();
		out << "\nassert_nca(!(o -> d -> _is_local() && "
		    << "o -> d -> _is_dynamic()), OBNCADynamicAsStatic);";
		out << "\nassert(!o -> d -> _is_local());";
		out << "\nval = new " << absolute << ';';
		out << "\nval -> _OB_copyFrom(o -> d);";
		out << "\nOBObjAny* no = new OBObjAny;";
		out << "\nno -> b = "
		    << "CORBA_Object::_duplicate(o -> b);";
		out << "\nno -> d = val;";
		out << "\n((CORBA_Any&)any).replace("
		    << scope << pre << "_tc_" << name << ", no, true);";
		out.end();
		out.end();
		out << "\nelse";
		out.inc();
		out << "\nval = " << absolute << "::_nil();";
		out.dec();
		out.sep();
		out << "\nreturn true;";
		out.end();
		out << "\nelse";
		out.inc();
		out << "\nreturn false;";
		out.dec();
		out.end();
	    }
	    
	    break;
	}

	case CORBA_dk_Alias:
	{
	    if(!noTC_)
	    {
		//
		// Alias
		//
		CORBA_TypeDescription* desc;
		CORBA_Boolean b = seq[i].value >>= desc;
		assert(b);
		
		if(!check(desc -> id))
		    continue;

		CORBA_Identifier_var name = fixKwd(desc -> name);
		CORBA_ScopedName_var absolute = getAbsolute(desc -> id);
		
		comment(desc -> id, out);
		
		//
		// TypeCode constant
		//
		out.sep();
		out << "\nOBTypeCodeConst " << scope << pre
		    << "_tc_" << name << '(';
		IdlOutputAsciiTypeCode(desc -> type, out);
		out << ");";
	    }

	    break;
	}

	case CORBA_dk_Enum:
	{
	    if(!noTC_)
	    {
		//
		// Enum
		//
		CORBA_TypeDescription* desc;
		CORBA_Boolean b = seq[i].value >>= desc;
		assert(b);
		
		if(!check(desc -> id))
		    continue;
		
		CORBA_Identifier_var name = fixKwd(desc -> name);
		CORBA_ScopedName_var absolute = getAbsolute(desc -> id);
		
		comment(desc -> id, out);
		
		//
		// TypeCode constant
		//
		out.sep();
		out << "\nOBTypeCodeConst " << scope << pre
		    << "_tc_" << name << '(';
		IdlOutputAsciiTypeCode(desc -> type, out);
		out << ");";
		
		//
		// Any insertion and extraction
		//
		out.sep();
		out << "\nvoid\noperator<<=(CORBA_Any& any, " << absolute
		    << " val)";
		out.start();
		out << "\nany.replace(" << scope << pre << "_tc_" << name
		    << ", new CORBA_ULong((CORBA_ULong)val), true);";
		out.end();
		
		out.sep();
		out << "\nCORBA_Boolean\noperator>>=(const CORBA_Any& any, "
		    << absolute << "& val)";
		out.start();
		out << "\nif(any.check_type(" << scope << pre << "_tc_" << name
		    << "))";
		out.start();
		out << "\nval = (" << absolute
		    << ")(*(CORBA_ULong*)any.value());";
		out << "\nreturn true;";
		out.end();
		out << "\nelse";
		out.inc();
		out << "\nreturn false;";
		out.dec();
		out.end();
	    }

	    break;
	}

	case CORBA_dk_Struct:
	case CORBA_dk_Exception:
	{
	    CORBA_RepositoryId_var id;
	    CORBA_Identifier_var name;
	    CORBA_TypeCode_var type;
	    
	    if(seq[i].kind == CORBA_dk_Struct)
	    {
		//
		// Struct
		//
		CORBA_TypeDescription* desc;
		CORBA_Boolean b = seq[i].value >>= desc;
		assert(b);

		name = fixKwd(desc -> name);
		id = desc -> id;
		type = desc -> type;
	    }
	    else
	    {
		//
		// Exception
		//
		CORBA_ExceptionDescription* desc;
		CORBA_Boolean b = seq[i].value >>= desc;
		assert(b);

		name = fixKwd(desc -> name);
		id = desc -> id;
		type = desc -> type;
	    }

	    if(!check(id))
		continue;

	    CORBA_ScopedName_var absolute = getAbsolute(id);

	    comment(id, out);

	    bool variable = IdlIsVariable(type);

	    //
	    // _var type
	    //
	    if(seq[i].kind == CORBA_dk_Struct)
	    {
		out.sep();
		out.direct("\n#ifndef HAVE_NO_EXPLICIT_TEMPLATES");
		if(variable)
		    out << "\ntemplate class OBVarVar< " << absolute << " >;";
		else
		    out << "\ntemplate class OBFixVar< " << absolute << " >;";
		out.direct("\n#else");
		out.direct("\n#ifdef HAVE_PRAGMA_DEFINE");
		if(variable)
		    out << "\n#pragma define(OBVarVar< " << absolute << " >)";
		else
		    out << "\n#pragma define(OBFixVar< " << absolute << " >)";
		out.direct("\n#endif"); // HAVE_PRAGMA_DEFINE
		out.direct("\n#endif"); // HAVE_NO_EXPLICIT_TEMPLATES
	    }

	    if(variable)
	    {
		//
		// Constructor(s) and assignment operator
		//
		bool hasFixed = false;
		for(j = 0 ; j < type -> member_count() ; j++)
		{
		    CORBA_TypeCode_var tc = type -> member_type(j);
		    if(!IdlIsVariable(tc))
		    {
			hasFixed = true;
			break;
		    }
		}
		if(hasFixed)
		{
		    out.sep();
		    out.direct("\n#ifdef OB_CLEAR_MEM");
		    out << '\n' << absolute << "::" << pre << name << "()";
		    out.start();
		    for(j = 0 ; j < type -> member_count() ; j++)
		    {
			CORBA_TypeCode_var tc = type -> member_type(j);
			if(!IdlIsVariable(tc))
			{
			    CORBA_Identifier_var memberName =
				type -> member_name(j);
			    out << "\nmemset(&" << memberName << ", 0, sizeof("
				<< memberName << "));";
			}
		    }
		    out.end();
		    out.direct("\n#endif"); // OB_CLEAR_MEM
		}

		out.sep();
		out << '\n' << absolute << "::" << pre << name << "(const "
		    << absolute << "& _ob_a)";
		out.inc();
		bool first = true;
		if(seq[i].kind == CORBA_dk_Exception)
		{
		    out << "\n: CORBA_UserException(_ob_a)";
		    first = false;
		}
		for(j = 0 ; j < type -> member_count() ; j++)
		{
		    CORBA_TypeCode_var tc = type -> member_type(j);
		    tc = OBGetOrigType(tc);
		    
		    if(tc -> kind() != CORBA_tk_array)
		    {
			if(first)
			{
			    first = false;
			    out << "\n: ";
			}
			else
			    out << ",\n  ";
			
			CORBA_Identifier_var memberName =
			    type -> member_name(j);
			memberName = fixKwd(memberName);
			out << memberName << "(_ob_a." << memberName << ')';
		    }
		}
		out.dec();
		out.start();
		for(j = 0 ; j < type -> member_count() ; j++)
		{
		    CORBA_TypeCode_var tc = type -> member_type(j);
		    tc = OBGetOrigType(tc);
		    
		    if(tc -> kind() == CORBA_tk_array)
		    {
			CORBA_Identifier_var memberName =
			    type -> member_name(j);
			memberName = fixKwd(memberName);

			CORBA_ScopedName_var arrayAbsolute =
			    getTypeString("", tc, GetTypeNormal, true);
			CORBA_String_var anon = IdlGetAnonName(arrayAbsolute);
			
			out << "\nOBCopy_" << anon << "(_ob_a."
			    << memberName << ", " << memberName << ");";
		    }
		}
		out.end();

		if(seq[i].kind == CORBA_dk_Exception &&
		   type -> member_count() > 0)
		{
		    out.sep();
		    out << '\n' << absolute << "::" << pre << name << '(';
		    unsigned int indent = out.getIndent();
		    out.setIndent(out.getPos());
		    for(j = 0 ; j < type -> member_count() ; j++)
		    {
			CORBA_String_var arg = CORBA_string_dup("_ob_a");
			arg += j;

			CORBA_TypeCode_var memberType = type -> member_type(j);
			CORBA_String_var s = getTypeString(scope, memberType,
							   GetTypeIn,
							   false, arg);
			
			if(j > 0)
			    out << ",\n";
			
			out << s;
		    }
		    out << ')';
		    out.setIndent(indent);
		    out.inc();
		    bool first = true;
		    for(j = 0 ; j < type -> member_count() ; j++)
		    {
			CORBA_TypeCode_var memberType = type -> member_type(j);
			CORBA_TypeCode_var tc = OBGetOrigType(memberType);
			
			if(tc -> kind() != CORBA_tk_array)
			{
			    if(first)
			    {
				first = false;
				out << "\n: ";
			    }
			    else
				out << ",\n  ";
			    
			    CORBA_Identifier_var memberName =
				type -> member_name(j);
			    memberName = fixKwd(memberName);
			    if(tc -> kind() == CORBA_tk_objref ||
			       tc -> kind() == CORBA_tk_Principal ||
			       tc -> kind() == CORBA_tk_TypeCode)
			    {
				CORBA_String_var s =
				    getTypeString(scope, memberType,
						  GetTypeNormal);
				out << memberName << '(' << s
				    << "::_duplicate(_ob_a" << j << "))";
			    }
			    else
				out << memberName << "(_ob_a" << j << ')';
			}
		    }
		    out.dec();
		    out.start();
		    for(j = 0 ; j < type -> member_count() ; j++)
		    {
			CORBA_TypeCode_var tc = type -> member_type(j);
			tc = OBGetOrigType(tc);
			
			if(tc -> kind() == CORBA_tk_array)
			{
			    CORBA_Identifier_var memberName =
				type -> member_name(j);
			    memberName = fixKwd(memberName);

			    CORBA_ScopedName_var arrayAbsolute =
				getTypeString("", tc, GetTypeNormal, true);
			    CORBA_String_var anon =
				IdlGetAnonName(arrayAbsolute);
			    
			    out << "\nOBCopy_" << anon << "(_ob_a" << j
				<< ", " << memberName << ");";
			}
		    }
		    out.end();
		}

		out.sep();
		out << '\n' << absolute << "&\n" << absolute
		    << "::operator=(const " << pre << name << '&';
		if(type -> member_count() > 0)
		    out << " _ob_a)";
		else
		    out << ')';
		out.start();
		if(type -> member_count() > 0)
		{
		    out << "\nif(this != &_ob_a)";
		    out.start();
		    
		    for(j = 0 ; j < type -> member_count() ; j++)
		    {
			CORBA_TypeCode_var tc = type -> member_type(j);
			tc = OBGetOrigType(tc);
			
			CORBA_Identifier_var memberName =
			    type -> member_name(j);
			memberName = fixKwd(memberName);
			
			if(tc -> kind() == CORBA_tk_array)
			{
			    CORBA_ScopedName_var arrayAbsolute =
				getTypeString("", tc, GetTypeNormal, true);
			    CORBA_String_var anon =
				IdlGetAnonName(arrayAbsolute);
			
			    out << "\nOBCopy_" << anon << "(_ob_a."
				<< memberName << ", " << memberName << ");";
			}
			else
			    out << '\n' << memberName << " = _ob_a."
				<< memberName << ';';
		    }
		    out.end();
		}
		out << "\nreturn *this;";
		out.end();
	    }

	    if(seq[i].kind == CORBA_dk_Exception)
	    {
		//
		// _narrow
		//
		out.sep();
		out << '\n' << absolute << "*\n" << absolute
		    << "::_narrow(CORBA_Exception* p)";
		out.start();
		out.direct("\n#ifdef HAVE_NO_RTTI");
		out << "\nif(p)";
		out.inc();
		out << "\nreturn (" << pre << name
		    << "*)(p -> _OB_narrowHelp(\"" << id << "\"));";
		out.dec();
		out << "\nelse";
		out.inc();
		out << "\nreturn 0;";
		out.dec();
		out.direct("\n#else"); // HAVE_NO_RTTI
		out << "\nreturn dynamic_cast<" << absolute << "*>(p);";
		out.direct("\n#endif"); // HAVE_NO_RTTI
		out.end();
		
		//
		// _OB_narrowHelp
		//
		out.sep();
		out.direct("\n#ifdef HAVE_NO_RTTI");
		out << "\nvoid*\n" << absolute
		    << "::_OB_narrowHelp(const char* _ob_id) const";
		out.start();
		out << "\nif(strcmp(\"" << id << "\", _ob_id) == 0)";
		out.inc();
		out << "\nreturn (void*)this;";
		out.dec();
		out << "\nelse";
		out.inc();
		out << "\nreturn CORBA_UserException::"
		    << "_OB_narrowHelp(_ob_id);";
		out.dec();
		out.end();
		out.direct("\n#endif"); // HAVE_NO_RTTI
		
		//
		// _OB_typeId
		//
		out.sep();
		out << "\nconst char*\n" << absolute << "::_OB_typeId() const";
		out.start();
		out << "\nreturn \"" << id << "\";";
		out.end();

		//
		// _OB_clone
		//
		out.sep();
		out << "\nCORBA_Exception*\n" << absolute
		    << "::_OB_clone() const";
		out.start();
		out << "\nreturn new " << pre << name << "(*this);";
		out.end();
	    }

	    if(!local_)
	    {
		//
		// CDR functions
		//
		// For exceptions, only the exception content is
		// marshaled/unmarshaled, not the exception id
		//
		out.sep();
		if(type -> member_count() > 0)
		    out << "\nvoid\nOBMarshal(const " << absolute
			<< "& val, CORBA_Octet*& oct)";
		else
		    out << "\nvoid\nOBMarshal(const " << absolute
			<< "&, CORBA_Octet*& oct)";
		out.start();
		if(seq[i].kind == CORBA_dk_Exception)
		    out << "\nOBMarshal(\"" << id << "\", oct);";
		for(j = 0 ; j < type -> member_count() ; j++)
		{
		    CORBA_Identifier_var memberName = type -> member_name(j);
		    memberName = fixKwd(memberName);
		    CORBA_TypeCode_var memberType = type -> member_type(j);
		    CORBA_String_var arg = CORBA_string_dup("val.");
		    arg += memberName;
		    writeMarshalCode(memberType, true, arg, "oct", out);
		}
		out.end();
		
		out.sep();
		if(type -> member_count() > 0)
		    out << "\nvoid\nOBMarshalCount(const " << absolute
			<< "& val, CORBA_ULong& count)";
		else
		    out << "\nvoid\nOBMarshalCount(const " << absolute
			<< "&, CORBA_ULong& count)";
		out.start();
		if(seq[i].kind == CORBA_dk_Exception)
		    out << "\nOBMarshalCount(\"" << id << "\", count);";
		for(j = 0 ; j < type -> member_count() ; j++)
		{
		    CORBA_Identifier_var memberName = type -> member_name(j);
		    memberName = fixKwd(memberName);
		    CORBA_TypeCode_var memberType = type -> member_type(j);
		    CORBA_String_var arg = CORBA_string_dup("val.");
		    arg += memberName;
		    writeMarshalCountCode(memberType, true, arg, "count", out);
		}
		out.end();
		
		out.sep();
		if(type -> member_count() > 0)
		    out << "\nvoid\nOBUnmarshal(" << absolute
			<< "& val, const CORBA_Octet*& coct, bool swap)";
		else
		    out << "\nvoid\nOBUnmarshal(" << absolute
			<< "&, const CORBA_Octet*& coct, bool swap)";
		out.start();
		if(seq[i].kind == CORBA_dk_Exception)
		{
		    out << "\nCORBA_String_var id;";
		    out << "\nOBUnmarshal(id.inout(), coct, swap);";
		    out << "\nassert(strcmp(id, \"" << id << "\") == 0);";
		}
		for(j = 0 ; j < type -> member_count() ; j++)
		{
		    CORBA_Identifier_var memberName = type -> member_name(j);
		    memberName = fixKwd(memberName);
		    CORBA_TypeCode_var memberType = type -> member_type(j);
		    CORBA_String_var arg = CORBA_string_dup("val.");
		    arg += memberName;
		    writeUnmarshalCode(memberType, true, arg, "coct", "swap",
				       out);
		}
		out.end();
	    }

	    if(!noTC_)
	    {
		//
		// TypeCode constant
		//
		out.sep();
		out << "\nOBTypeCodeConst " << scope << pre
		    << "_tc_" << name << '(';
		IdlOutputAsciiTypeCode(type, out);
		out << ");";
		
		//
		// Any insertion and extraction
		//
		out.sep();
		out.direct("\n#ifndef HAVE_NO_EXPLICIT_TEMPLATES");
		out << "\ntemplate class OBInfo< " << absolute << " >;";
		out.direct("\n#else");
		out.direct("\n#ifdef HAVE_PRAGMA_DEFINE");
		out << "\n#pragma define(OBInfo< " << absolute << " >)";
		out.direct("\n#endif"); // HAVE_PRAGMA_DEFINE
		out.direct("\n#endif"); // HAVE_NO_EXPLICIT_TEMPLATES
		out.sep();
		out << "\nvoid\noperator<<=(CORBA_Any& any, " << absolute
		    << "* p)";
		out.start();
		out << "\nstatic const OBInfo< " << absolute << " > info;";
		out << "\nany.replace(" << scope << pre << "_tc_" << name
		    << ", p, true, &info);";
		out.end();
		
		out.sep();
		out << "\nvoid\noperator<<=(CORBA_Any& any, const " << absolute
		    << "& val)";
		out.start();
		out << '\n' << absolute << "* p = new " << absolute
		    << "(val);";
		out << "\nstatic const OBInfo< " << absolute << " > info;";
		out << "\nany.replace(" << scope << pre << "_tc_" << name
		    << ", p, true, &info);";
		out.end();
		
		out.sep();
		out << "\nCORBA_Boolean\noperator>>=(const CORBA_Any& any, "
		    << absolute << "*& p)";
		out.start();
		out << "\nif(any.check_type(" << scope << pre << "_tc_" << name
		    << "))";
		out.start();
		out << "\nif(!any.info())";
		out.start();
		out << "\nconst OBBuffer* cbufp = "
		    << "(const OBBuffer*)any.value();";
		out << "\nconst CORBA_Octet* coct = cbufp -> data;";
		out << '\n' << absolute << "* v = new " << absolute << ';';
		out << "\nOBUnmarshal(*v, coct, false);";
		out << "\n(CORBA_Any&)any <<= v;";
		out.end();
		out.sep();
		out << "\np = (" << absolute << "*)any.value();";
		out << "\nreturn true;";
		out.end();
		out << "\nelse";
		out.inc();
		out << "\nreturn false;";
		out.dec();
		out.end();
	    }

	    break;
	}

	case CORBA_dk_Union:
	{
	    //
	    // Union
	    //
	    CORBA_TypeDescription* desc;
	    CORBA_Boolean b = seq[i].value >>= desc;
	    assert(b);

	    if(!check(desc -> id))
		continue;

	    CORBA_Identifier_var name = fixKwd(desc -> name);
	    CORBA_ScopedName_var absolute = getAbsolute(desc -> id);

	    CORBA_TypeCode_var discType = desc -> type -> discriminator_type();
	    CORBA_TypeCode_var origDiscType = OBGetOrigType(discType);

	    CORBA_String_var disc = getTypeString(scope, discType,
						  GetTypeNormal);

	    CORBA_String_var absDisc = getTypeString("", discType,
						     GetTypeNormal);

	    CORBA_String_var cast;
	    CORBA_String_var absCast;
	    if(origDiscType -> kind() == CORBA_tk_enum)
	    {
		cast = CORBA_string_alloc(1 + strlen(disc) + 1);
		strcpy(cast.inout(), "(");
		strcat(cast.inout(), disc);
		strcat(cast.inout(), ")");

		absCast = CORBA_string_alloc(1 + strlen(absDisc) + 1);
		strcpy(absCast.inout(), "(");
		strcat(absCast.inout(), absDisc);
		strcat(absCast.inout(), ")");
	    }
	    else
	    {
		cast = CORBA_string_dup("");
		absCast = CORBA_string_dup("");
	    }

	    IdlUnionMemberInfoSeq_var infoSeq =	IdlGetUnionInfo(desc -> type);
	    for(j = 0 ; j < infoSeq -> length() ; j++)
		infoSeq[j].name = fixKwd(infoSeq[j].name);

	    bool variable = IdlIsVariable(desc -> type);

	    comment(desc -> id, out);

	    //
	    // _var type
	    //
	    out.sep();
	    out.direct("\n#ifndef HAVE_NO_EXPLICIT_TEMPLATES");
	    if(variable)
		out << "\ntemplate class OBVarVar< " << absolute << " >;";
	    else
		out << "\ntemplate class OBFixVar< " << absolute << " >;";
	    out.direct("\n#else");
	    out.direct("\n#ifdef HAVE_PRAGMA_DEFINE");
	    if(variable)
		out << "\n#pragma define(OBVarVar< " << absolute << " >)";
	    else
		out << "\n#pragma define(OBFixVar< " << absolute << " >)";
	    out.direct("\n#endif"); // HAVE_PRAGMA_DEFINE
	    out.direct("\n#endif"); // HAVE_NO_EXPLICIT_TEMPLATES
	    
	    //
	    // The remove function
	    //
	    if(variable)
	    {
		out.sep();
		out << "\nvoid\n" << absolute << "::_OB_remove()";
		out.start();
		out << "\nif(_ob_i_)";
		out.start();
		out << "\nswitch(_ob_d_)";
		out.start();
		for(j = 0; j < infoSeq -> length() ; j++)
		{
		    IdlUnionMemberInfo& info = infoSeq[j];
		    
		    if(j > 0)
			out.sep();
		    
		    printUnionLabels(info, out, cast);
		    
		    if(!CORBA_is_nil(info.type))
		    {
			CORBA_String_var norm =
			    getTypeString(scope, info.type, GetTypeNormal);
			
			CORBA_TypeCode_var origMemberType =
			    OBGetOrigType(info.type);
			
			switch(origMemberType -> kind())
			{
			case CORBA_tk_null:
			case CORBA_tk_void:
			case CORBA_tk_except:
			    assert(false);
			    break;
			    
			case CORBA_tk_short:
			case CORBA_tk_long:
			case CORBA_tk_ushort:
			case CORBA_tk_ulong:
			case CORBA_tk_float:
			case CORBA_tk_double:
			case CORBA_tk_boolean:
			case CORBA_tk_char:
			case CORBA_tk_octet:
			case CORBA_tk_enum:
			    break;
			    
			case CORBA_tk_struct:
			case CORBA_tk_union:
			case CORBA_tk_sequence:
			case CORBA_tk_any:
			    
			    if(IdlIsVariable(origMemberType))
				out << "\ndelete _ob_v_." << info.name << ';';
			    break;
			    
			case CORBA_tk_TypeCode:
			case CORBA_tk_Principal:
			case CORBA_tk_objref:
			    
			    out << "\nCORBA_release(_ob_v_." << info.name
				<< ");";
			    break;
			    
			case CORBA_tk_string:
			    
			    out << "\nCORBA_string_free(_ob_v_." << info.name
				<< ");";
			    break;
			    
			case CORBA_tk_array:
			    
			    if(IdlIsVariable(origMemberType))
			    {
				CORBA_ScopedName_var arrayAbsolute =
				    getTypeString("", info.type,
						  GetTypeNormal, true);
				CORBA_String_var anon =
				    IdlGetAnonName(arrayAbsolute);
				
				out << "\nOBFree_" << anon << "(_ob_v_."
				    << info.name << ");";
			    }
			    break;
			    
			case CORBA_tk_alias:
			    assert(false);
			    break;
			}
		    }
		    
		    out << "\nbreak;";
		}
		out.end();
		out.sep();
		out << "\n_ob_i_ = false;";
		out.end();
		out.end();
	    }

	    //
	    // The check function
	    //
	    out.sep();
	    out << "\nbool\n" << absolute << "::_OB_check(" << disc
		<< " _ob_d) const";
	    out.start();
	    if(variable)
	    {
		out << "\nassert_nca(_ob_i_, OBNCAUnionInit);";
		out.sep();
	    }
	    bool needSwitch = false;
	    for(j = 0 ; j < infoSeq -> length() ; j++)
	    {
		IdlUnionMemberInfo& info = infoSeq[j];
		if(info.nLabels.length() + info.pLabels.length() > 1 ||
		   info.isDefault)
		{
		    needSwitch = true;
		    break;
		}
	    }
	    if(needSwitch)
	    {
		out << '\n' << disc << " d[2];";
		out << "\nd[0] = _ob_d;";
		out << "\nd[1] = _ob_d_;";
		out.sep();
		out << "\nfor(int i = 0 ; i < 2 ; i++)";
		out.start();
		out << "\nswitch(d[i])";
		out.start();
		for(j = 0 ; j < infoSeq -> length() ; j++)
		{
		    IdlUnionMemberInfo& info = infoSeq[j];
		    
		    if(j > 0)
			out.sep();
		    
		    printUnionLabels(info, out, cast);
		    
		    if(info.nLabels.length() + info.pLabels.length() > 1 ||
		       info.isDefault)
		    {
			if(info.pLabels.length() > 0)
			    out << "\nd[i] = " << cast
				<< info.pLabels[0] << ';';
			else
			    out << "\nd[i] = " << cast << '-'
				<< info.nLabels[0] << ';';
		    }
		    
		    out << "\nbreak;";
		}
		out.end();
		out.end();
		out.sep();
		out << "\nreturn d[0] == d[1];";
	    }
	    else
	    {
		out << "\nreturn _ob_d == _ob_d_;";
	    }
	    out.end();

	    if(variable)
	    {
		//
		// Default constructor
		//
		out.sep();
		out.direct("\n#ifdef OB_CLEAR_MEM");
		out << '\n' << absolute << "::" << pre << name << "()";
		out.inc();
		out << "\n: _ob_i_(false)";
		out.dec();
		out.start();
		out << "\nmemset(&_ob_v_, 0, sizeof(_ob_v_));";
		out << "\nmemset(&_ob_d_, 0, sizeof(_ob_d_));";
		out.end();
		out.direct("\n#endif"); // OB_CLEAR_MEM
		
		//
		// Copy constructor
		//
		out.sep();
		out << '\n' << absolute << "::" << pre << name << "(const "
		    << pre << name << "& _ob_a)";
		out.inc();
		out << "\n: _ob_i_(false)";
		out.dec();
		out.start();
		out << "\n*this = _ob_a;";
		out.end();
		
		//
		// Assignment operator
		//
		out.sep();
		out << '\n' << absolute << "&\n" << absolute << "::operator="
		    << "(const " << pre << name << "& _ob_a)";
		out.start();
		out << "\nif(this != &_ob_a)";
		out.start();
		out << "\n_OB_remove();";
		out.sep();
		out << "\nif(_ob_a._ob_i_)";
		out.start();
		out << "\n_ob_i_ = true;";
		out << "\n_ob_d_ = _ob_a._ob_d_;";
		out << "\nswitch(_ob_d_)";
		out.start();
		for(j = 0 ; j < infoSeq -> length() ; j++)
		{
		    IdlUnionMemberInfo& info = infoSeq[j];
		    
		    if(j > 0)
			out.sep();
		    
		    printUnionLabels(info, out, cast);
		    
		    if(!CORBA_is_nil(info.type))
		    {
			CORBA_String_var norm =
			    getTypeString(scope, info.type, GetTypeNormal);
			
			CORBA_TypeCode_var origMemberType =
			    OBGetOrigType(info.type);
			
			switch(origMemberType -> kind())
			{
			case CORBA_tk_null:
			case CORBA_tk_void:
			case CORBA_tk_except:
			    assert(false);
			    break;
			    
			case CORBA_tk_short:
			case CORBA_tk_long:
			case CORBA_tk_ushort:
			case CORBA_tk_ulong:
			case CORBA_tk_float:
			case CORBA_tk_double:
			case CORBA_tk_boolean:
			case CORBA_tk_char:
			case CORBA_tk_octet:
			case CORBA_tk_enum:
			    
			    out << "\n_ob_v_." << info.name
				<< " = _ob_a._ob_v_." << info.name << ';';
			    break;
			    
			case CORBA_tk_struct:
			case CORBA_tk_union:
			case CORBA_tk_sequence:
			case CORBA_tk_any:
			
			    if(IdlIsVariable(origMemberType))
			    {
				out << "\n_ob_v_." << info.name
				    << " = new " << norm << "(*_ob_a._ob_v_."
				    << info.name << ");";
			    }
			    else
			    {
				out << "\n_ob_v_." << info.name
				    << " = _ob_a._ob_v_." << info.name << ';';
			    }
			    break;
			    
			case CORBA_tk_TypeCode:
			case CORBA_tk_Principal:
			case CORBA_tk_objref:
			    
			    out << "\n_ob_v_." << info.name << " = " << norm
				<< "::_duplicate(_ob_a._ob_v_."
				<< info.name << ");";
			    break;
			    
			case CORBA_tk_string:
			    
			    out << "\n_ob_v_." << info.name
				<< " = CORBA_string_dup(_ob_a._ob_v_."
				<< info.name << ");";
			    break;
			    
			case CORBA_tk_array:
			{
			    CORBA_ScopedName_var arrayAbsolute =
				getTypeString("", info.type, GetTypeNormal,
					      true);
			    CORBA_String_var anon =
				IdlGetAnonName(arrayAbsolute);

			    if(IdlIsVariable(origMemberType))
			    {
				out << "\n_ob_v_." << info.name
				    << " = OBDup_" << anon
				    << "(_ob_a._ob_v_." << info.name << ");";
			    }
			    else
			    {
				out << "\nOBCopy_" << anon << "(_ob_a._ob_v_."
				    << info.name << ", _ob_v_."
				    << info.name << ");";
			    }
			    
			    break;
			}
			
			case CORBA_tk_alias:
			    assert(false);
			    break;
			}
		    }
		    
		    out << "\nbreak;";
		}
		out.end();
		out.end();
		out.end();
		out.sep();
		out << "\nreturn *this;";
		out.end();
	    }
	    
	    //
	    // Set and get discriminant value
	    //
	    out.sep();
	    out << "\nvoid\n" << absolute << "::_d(" << disc << " _ob_d)";
	    out.start();
	    out << "\nassert_nca(_OB_check(_ob_d), OBNCADiscMismatch);";
	    out << "\n_ob_d_ = _ob_d;";
	    out.end();

	    out.sep();
	    out << '\n' << absDisc << '\n' << absolute << "::_d() const";
	    out.start();
	    if(variable)
		out << "\nassert_nca(_ob_i_, OBNCAUnionInit);";
	    out << "\nreturn _ob_d_;";
	    out.end();

	    //
	    // Set and get functions
	    //
	    for(j = 0 ; j < infoSeq -> length() ; j++)
	    {
		IdlUnionMemberInfo& info = infoSeq[j];

		CORBA_String_var label = cast;
		if(info.pLabels.length() > 0)
		{
		    label += info.pLabels[0];
		}
		else
		{
		    label += '-';
		    label += info.nLabels[0];
		}

		if(CORBA_is_nil(info.type))
		{
		    out.sep();
		    out << "\nvoid\n" << absolute << "::_default()";
		    out.start();
		    if(variable)
		    {
			out << "\n_OB_remove();";
			out << "\n_ob_i_ = true;";
		    }
		    out << "\n_ob_d_ = " << label << ';';
		    out.end();
		}
		else
		{
		    CORBA_String_var norm =
			getTypeString(scope, info.type, GetTypeNormal);

		    CORBA_String_var absNorm =
			getTypeString("", info.type, GetTypeNormal);

		    CORBA_TypeCode_var origMemberType =
			OBGetOrigType(info.type);

		    switch(origMemberType -> kind())
		    {
		    case CORBA_tk_null:
		    case CORBA_tk_void:
		    case CORBA_tk_except:
			assert(false);
			break;
			
		    case CORBA_tk_short:
		    case CORBA_tk_long:
		    case CORBA_tk_ushort:
		    case CORBA_tk_ulong:
		    case CORBA_tk_float:
		    case CORBA_tk_double:
		    case CORBA_tk_boolean:
		    case CORBA_tk_char:
		    case CORBA_tk_octet:
		    case CORBA_tk_enum:
			
			out.sep();
			out << "\nvoid\n" << absolute << "::"
			    << info.name << '(' << norm << " _ob_a)";
			out.start();
			if(variable)
			{
			    out << "\n_OB_remove();";
			    out << "\n_ob_i_ = true;";
			}
			out << "\n_ob_d_ = " << label << ';';
			out << "\n_ob_v_." << info.name << " = _ob_a;";
			out.end();
			
			out.sep();
			out << '\n' << absNorm << '\n' << absolute << "::"
			    << info.name << "() const";
			out.start();
			out << "\nassert_nca(_OB_check(" << label
			    << "), OBNCADiscMismatch);";
			out << "\nreturn _ob_v_." << info.name << ';';
			out.end();
			break;
			
		    case CORBA_tk_struct:
		    case CORBA_tk_union:
		    case CORBA_tk_sequence:
		    case CORBA_tk_any:
			
			out.sep();
			out << "\nvoid\n" << absolute << "::"
			    << info.name << "(const " << norm << "& _ob_a)";
			out.start();
			if(variable)
			{
			    out << "\n_OB_remove();";
			    out << "\n_ob_i_ = true;";
			}
			out << "\n_ob_d_ = " << label << ';';
			if(IdlIsVariable(origMemberType))
			{
			    out << "\n_ob_v_." << info.name << " = new "
				<< norm	<< "(_ob_a);";
			}
			else
			{
			    out << "\n_ob_v_." << info.name << " = _ob_a;";
			}
			out.end();
			
			out.sep();
			out << "\nconst " << absNorm << "&\n" << absolute
			    << "::" << info.name << "() const";
			out.start();
			out << "\nassert_nca(_OB_check(" << label
			    << "), OBNCADiscMismatch);";
			if(IdlIsVariable(origMemberType))
			{
			    out << "\nreturn *_ob_v_." << info.name << ';';
			}
			else
			{
			    out << "\nreturn _ob_v_." << info.name << ';';
			}
			out.end();
			
			out.sep();
			out << '\n' << absNorm << "&\n" << absolute << "::"
			    << info.name << "()";
			out.start();
			out << "\nassert_nca(_OB_check(" << label
			    << "), OBNCADiscMismatch);";
			if(IdlIsVariable(origMemberType))
			{
			    out << "\nreturn *_ob_v_." << info.name << ';';
			}
			else
			{
			    out << "\nreturn _ob_v_." << info.name << ';';
			}
			out.end();
			
			break;
			
		    case CORBA_tk_TypeCode:
		    case CORBA_tk_Principal:
		    case CORBA_tk_objref:
			
			out.sep();
			out << "\nvoid\n" << absolute << "::"
			    << info.name << '(' << norm << "_ptr _ob_a)";
			out.start();
			if(variable)
			{
			    out << "\n_OB_remove();";
			    out << "\n_ob_i_ = true;";
			}
			out << "\n_ob_d_ = " << label << ';';
			out << "\n_ob_v_." << info.name << " = " << norm
			    << "::_duplicate(_ob_a);";
			out.end();
			
			out.sep();
			out << '\n' << absNorm << "_ptr\n" << absolute << "::"
			    << info.name << "() const";
			out.start();
			out << "\nassert_nca(_OB_check(" << label
			    << "), OBNCADiscMismatch);";
			out << "\nreturn _ob_v_." << info.name << ';';
			out.end();
			
			break;
			
		    case CORBA_tk_string:
			
			out.sep();
			out << "\nvoid\n" << absolute << "::" << info.name
			    << "(char* _ob_a)";
			out.start();
			if(variable)
			{
			    out << "\n_OB_remove();";
			    out << "\n_ob_i_ = true;";
			}
			out << "\n_ob_d_ = " << label << ';';
			out << "\n_ob_v_." << info.name << " = _ob_a;";
			out.end();
			
			out.sep();
			out << "\nvoid\n" << absolute << "::"
			    << info.name << "(const char* _ob_a)";
			out.start();
			if(variable)
			{
			    out << "\n_OB_remove();";
			    out << "\n_ob_i_ = true;";
			}
			out << "\n_ob_d_ = " << label << ';';
			out << "\n_ob_v_." << info.name
			    << " = CORBA_string_dup(_ob_a);";
			out.end();
			
			out.sep();
			out << "\nvoid\n" << absolute << "::" << info.name
			    << "(const CORBA_String_var& _ob_a)";
			out.start();
			if(variable)
			{
			    out << "\n_OB_remove();";
			    out << "\n_ob_i_ = true;";
			}
			out << "\n_ob_d_ = " << label << ';';
			out << "\n_ob_v_." << info.name
			    << " = CORBA_string_dup(_ob_a);";
			out.end();
			
			out.sep();
			out << "\nconst char*\n" << absolute << "::"
			    << info.name << "() const";
			out.start();
			out << "\nassert_nca(_OB_check(" << label
			    << "), OBNCADiscMismatch);";
			out << "\nreturn _ob_v_." << info.name << ';';
			out.end();
			
			break;
			
		    case CORBA_tk_array:
		    {
			CORBA_String_var slice;
			CORBA_String_var absSlice;
			
			if(info.type -> kind() == CORBA_tk_alias)
			{
			    slice = getTypeString(scope, info.type,
						  GetTypeSlice);

			    absSlice = getTypeString("", info.type,
						     GetTypeSlice);
			}
			else
			{
			    const char* sl = "_slice";
			    slice = CORBA_string_alloc(1 + strlen(info.name)
						       + strlen(sl));
			    strcpy(slice.inout(), "_");
			    strcat(slice.inout(), info.name);
			    strcat(slice.inout(), sl);

			    absSlice = CORBA_string_alloc(strlen(absolute) +
							  + 2 + strlen(slice));
			    strcpy(absSlice.inout(), absolute);
			    strcat(absSlice.inout(), "::");
			    strcat(absSlice.inout(), slice);
			}
			
			CORBA_ScopedName_var arrayAbsolute =
			    getTypeString("", info.type, GetTypeNormal, true);
			CORBA_String_var anon = IdlGetAnonName(arrayAbsolute);
			
			out.sep();
			out << "\nvoid\n" << absolute << "::"
			    << info.name << '(' << slice << "* _ob_a)";
			out.start();
			if(variable)
			{
			    out << "\n_OB_remove();";
			    out << "\n_ob_i_ = true;";
			}
			out << "\n_ob_d_ = " << label << ';';
			if(IdlIsVariable(origMemberType))
			{
			    out << "\n_ob_v_." << info.name << " = OBDup_"
				<< anon << "(_ob_a);";
			}
			else
			{
			    out << "\nOBCopy_" << anon << "(_ob_a, _ob_v_."
				<< info.name << ");";
			}
			out.end();
			
			out.sep();
			out << '\n' << absSlice << "*\n" << absolute
			    << "::" << info.name << "()";
			out.start();
			out << "\nassert_nca(_OB_check(" << label
			    << "), OBNCADiscMismatch);";
			out << "\nreturn _ob_v_." << info.name << ';';
			out.end();
			
			out.sep();
			out << "\nconst " << absSlice << "*\n" << absolute
			    << "::" << info.name << "() const";
			out.start();
			out << "\nassert_nca(_OB_check(" << label
			    << "), OBNCADiscMismatch);";
			out.direct("\n#ifdef HAVE_VCPLUSPLUS_BUGS");
			out << "\nreturn (const " << slice << "*)_ob_v_."
			    << info.name << ';';
			out.direct("\n#else");
			out << "\nreturn _ob_v_." << info.name << ';';
			out.direct("\n#endif");
                        // HAVE_VCPLUSPLUS_BUGS
			out.end();
			
			break;
		    }
		    
		    case CORBA_tk_alias:
			assert(false);
			break;
		    }
		}
	    }

	    if(!local_)
	    {
		//
		// CDR
		//
		out.sep();
		out << "\nvoid\nOBMarshal(const " << absolute
		    << "& val, CORBA_Octet*& oct)";
		out.start();
		if(variable)
		    out << "\nassert_nca(val._ob_i_, OBNCAUnionInit);";
		out << "\nOBMarshal(val._ob_d_, oct);";
		out << "\nswitch(val._ob_d_)";
		out.start();
		for(j = 0 ; j < infoSeq -> length() ; j++)
		{
		    IdlUnionMemberInfo& info = infoSeq[j];
		    
		    if(j > 0)
			out.sep();
		    
		    printUnionLabels(info, out, absCast);
		    
		    if(!CORBA_is_nil(info.type))
		    {
			CORBA_TypeCode_var origMemberType =
			    OBGetOrigType(info.type);
			
			switch(origMemberType -> kind())
			{
			case CORBA_tk_null:
			case CORBA_tk_void:
			case CORBA_tk_except:
			    assert(false);
			    break;
			    
			case CORBA_tk_short:
			case CORBA_tk_long:
			case CORBA_tk_ushort:
			case CORBA_tk_ulong:
			case CORBA_tk_float:
			case CORBA_tk_double:
			case CORBA_tk_boolean:
			case CORBA_tk_char:
			case CORBA_tk_octet:
			case CORBA_tk_enum:
			case CORBA_tk_TypeCode:
			case CORBA_tk_Principal:
			case CORBA_tk_objref:
			case CORBA_tk_string:
			    
			    out << "\nOBMarshal(val._ob_v_." << info.name
				<< ", oct);";
			    break;
			    
			case CORBA_tk_struct:
			case CORBA_tk_union:
			case CORBA_tk_sequence:
			case CORBA_tk_any:
			    
			    if(IdlIsVariable(origMemberType))
			    {
				out << "\nOBMarshal(*val._ob_v_." << info.name
				    << ", oct);";
			    }
			    else
			    {
				out << "\nOBMarshal(val._ob_v_." << info.name
				    << ", oct);";
			    }
			    break;
			    
			case CORBA_tk_array:
			{
			    CORBA_ScopedName_var arrayAbsolute =
				getTypeString("", info.type, GetTypeNormal,
					      true);
			    CORBA_String_var anon =
				IdlGetAnonName(arrayAbsolute);
			    
			    out << "\nOBMarshal_" << anon << "(val._ob_v_."
				<< info.name << ", oct);";
			    break;
			}
			
			case CORBA_tk_alias:
			    assert(false);
			    break;
			}
		    }
		    
		    out << "\nbreak;";
		}
		out.end();
		out.end();
		
		out.sep();
		out << "\nvoid\nOBMarshalCount(const " << absolute
		    << "& val, CORBA_ULong& count)";
		out.start();
		if(variable)
		    out << "\nassert_nca(val._ob_i_, OBNCAUnionInit);";
		out << "\nOBMarshalCount(val._ob_d_, count);";
		out << "\nswitch(val._ob_d_)";
		out.start();
		for(j = 0 ; j < infoSeq -> length() ; j++)
		{
		    IdlUnionMemberInfo& info = infoSeq[j];
		    
		    if(j > 0)
			out.sep();
		    
		    printUnionLabels(info, out, absCast);
		    
		    if(!CORBA_is_nil(info.type))
		    {
			CORBA_TypeCode_var origMemberType =
			    OBGetOrigType(info.type);
			
			switch(origMemberType -> kind())
			{
			case CORBA_tk_null:
			case CORBA_tk_void:
			case CORBA_tk_except:
			    assert(false);
			    break;
			    
			case CORBA_tk_short:
			case CORBA_tk_long:
			case CORBA_tk_ushort:
			case CORBA_tk_ulong:
			case CORBA_tk_float:
			case CORBA_tk_double:
			case CORBA_tk_boolean:
			case CORBA_tk_char:
			case CORBA_tk_octet:
			case CORBA_tk_enum:
			case CORBA_tk_TypeCode:
			case CORBA_tk_Principal:
			case CORBA_tk_objref:
			case CORBA_tk_string:
			    
			    out << "\nOBMarshalCount(val._ob_v_." << info.name
				<< ", count);";
			    break;
			    
			case CORBA_tk_struct:
			case CORBA_tk_union:
			case CORBA_tk_sequence:
			case CORBA_tk_any:
			    
			    if(IdlIsVariable(origMemberType))
			    {
				out << "\nOBMarshalCount(*val._ob_v_."
				    << info.name << ", count);";
			    }
			    else
			    {
				out << "\nOBMarshalCount(val._ob_v_."
				    << info.name << ", count);";
			    }
			    break;
			    
			case CORBA_tk_array:
			{
			    CORBA_ScopedName_var arrayAbsolute =
				getTypeString("", info.type, GetTypeNormal,
					      true);
			    CORBA_String_var anon =
				IdlGetAnonName(arrayAbsolute);
			    
			    out << "\nOBMarshalCount_" << anon
				<< "(val._ob_v_." << info.name << ", count);";
			    break;
			}
			
			case CORBA_tk_alias:
			    assert(false);
			    break;
			}
		    }
		    
		    out << "\nbreak;";
		}
		out.end();
		out.end();
		
		out.sep();
		out << "\nvoid\nOBUnmarshal(" << absolute
		    << "& val, const CORBA_Octet*& coct, bool swap)";
		out.start();
		if(variable)
		{
		    out << "\nval._OB_remove();";
		    out.sep();
		}
		if(variable)
		    out << "\nval._ob_i_ = true;";
		out << "\nOBUnmarshal(val._ob_d_, coct, swap);";
		out.sep();
		out << "\nswitch(val._ob_d_)";
		out.start();
		for(j = 0 ; j < infoSeq -> length() ; j++)
		{
		    IdlUnionMemberInfo& info = infoSeq[j];
		    
		    if(j > 0)
			out.sep();
		    
		    printUnionLabels(info, out, absCast);
		    
		    if(!CORBA_is_nil(info.type))
		    {
			CORBA_String_var norm =
			    getTypeString("", info.type, GetTypeNormal);
			
			CORBA_TypeCode_var origMemberType =
			    OBGetOrigType(info.type);
			
			switch(origMemberType -> kind())
			{
			case CORBA_tk_null:
			case CORBA_tk_void:
			case CORBA_tk_except:
			    assert(false);
			    break;
			    
			case CORBA_tk_short:
			case CORBA_tk_long:
			case CORBA_tk_ushort:
			case CORBA_tk_ulong:
			case CORBA_tk_float:
			case CORBA_tk_double:
			case CORBA_tk_boolean:
			case CORBA_tk_char:
			case CORBA_tk_octet:
			case CORBA_tk_enum:
			    
			    out << "\nOBUnmarshal(val._ob_v_." << info.name
				<< ", coct, swap);";
			    out << "\nbreak;";
			    break;
			    
			case CORBA_tk_struct:
			case CORBA_tk_union:
			case CORBA_tk_sequence:
			case CORBA_tk_any:
			    
			    if(IdlIsVariable(origMemberType))
			    {
				out.dec();
				out.start();
				out << '\n' << norm << "* p = new " << norm
				    << ';';
				out << "\nOBUnmarshal(*p, coct, swap);";
				out << "\nval._ob_v_." << info.name << " = p;";
				out << "\nbreak;";
				out.end();
				out.inc();
			    }
			    else
			    {
				out << "\nOBUnmarshal(val._ob_v_." << info.name
				    << ", coct, swap);";
				out << "\nbreak;";
			    }
			    break;
			    
			case CORBA_tk_TypeCode:
			case CORBA_tk_Principal:
			case CORBA_tk_objref:
			    
			    out.dec();
			    out.start();
			    out << '\n' << norm << "_ptr ref = " << norm
				<< "::_nil();";
			    out << "\nOBUnmarshal(ref, coct, swap);";
			    out << "\nval._ob_v_." << info.name << " = ref;";
			    out << "\nbreak;";
			    out.end();
			    out.inc();
			    break;
			    
			case CORBA_tk_string:
			    
			    out.dec();
			    out.start();
			    out << "\nchar* s = 0;";
			    out << "\nOBUnmarshal(s, coct, swap);";
			    out << "\nval._ob_v_." << info.name << " = s;";
			    out << "\nbreak;";
			    out.end();
			    out.inc();
			    break;
			    
			case CORBA_tk_array:
			{
			    CORBA_ScopedName_var arrayAbsolute =
				getTypeString("", info.type, GetTypeNormal,
					      true);
			    CORBA_String_var anon =
				IdlGetAnonName(arrayAbsolute);
			    
			    if(IdlIsVariable(origMemberType))
			    {
				
				out << "\nval._ob_v_." << info.name
				    << " = OBAlloc_" << anon << "();";
			    }
			    
			    out << "\nOBUnmarshal_" << anon << "(val._ob_v_."
				<< info.name << ", coct, swap);";
			    break;
			}
			
			case CORBA_tk_alias:
			    assert(false);
			    break;
			}
		    }
		    else
			out << "\nbreak;";
		}
		out.end();
		out.end();
	    }
	    
	    if(!noTC_)
	    {
		//
		// TypeCode constant
		//
		out.sep();
		out << "\nOBTypeCodeConst " << scope << pre
		    << "_tc_" << name << '(';
		IdlOutputAsciiTypeCode(desc -> type, out);
		out << ");";
		
		//
		// Any insertion and extraction
		//
		out.sep();
		out.direct("\n#ifndef HAVE_NO_EXPLICIT_TEMPLATES");
		out << "\ntemplate class OBInfo< " << absolute << " >;";
		out.direct("\n#else");
		out.direct("\n#ifdef HAVE_PRAGMA_DEFINE");
		out << "\n#pragma define(OBInfo< " << absolute << " >)";
		out.direct("\n#endif"); // HAVE_PRAGMA_DEFINE
		out.direct("\n#endif"); // HAVE_NO_EXPLICIT_TEMPLATES
		out.sep();
		out << "\nvoid\noperator<<=(CORBA_Any& any, " << absolute
		    << "* p)";
		out.start();
		out << "\nstatic const OBInfo< " << absolute << " > info;";
		out << "\nany.replace(" << scope << pre << "_tc_" << name
		    << ", p, true, &info);";
		out.end();
		
		out.sep();
		out << "\nvoid\noperator<<=(CORBA_Any& any, const " << absolute
		    << "& val)";
		out.start();
		out << '\n' << absolute << "* p = new " << absolute
		    << "(val);";
		out << "\nstatic const OBInfo< " << absolute << " > info;";
		out << "\nany.replace(" << scope << pre << "_tc_" << name
		    << ", p, true, &info);";
		out.end();
		
		out.sep();
		out << "\nCORBA_Boolean\noperator>>=(const CORBA_Any& any, "
		    << absolute << "*& p)";
		out.start();
		out << "\nif(any.check_type(" << scope << pre << "_tc_" << name
		    << "))";
		out.start();
		out << "\nif(!any.info())";
		out.start();
		out << "\nconst OBBuffer* cbufp = "
		    << "(const OBBuffer*)any.value();";
		out << "\nconst CORBA_Octet* coct = cbufp -> data;";
		out << '\n' << absolute << "* v = new " << absolute << ';';
		out << "\nOBUnmarshal(*v, coct, false);";
		out << "\n(CORBA_Any&)any <<= v;";
		out.end();
		out.sep();
		out << "\np = (" << absolute << "*)any.value();";
		out << "\nreturn true;";
		out.end();
		out << "\nelse";
		out.inc();
		out << "\nreturn false;";
		out.dec();
		out.end();
	    }

	    break;
	}

	case CORBA_dk_Attribute:
	{
	    //
	    // Attribute
	    //
	    if(local_)
		continue;

	    CORBA_AttributeDescription* desc;
	    CORBA_Boolean b = seq[i].value >>= desc;
	    assert(b);

	    if(!check(desc -> id))
		continue;

	    CORBA_Identifier_var name = fixKwd(desc -> name);
	    CORBA_ScopedName_var absolute = getAbsolute(desc -> id);

	    comment(desc -> id, out);

	    CORBA_String_var ret = getTypeString("", desc -> type,
						 GetTypeReturn, false);
	    out.sep();
	    out << '\n' << ret << '\n' << absolute << "()";
	    out.start();
	    out << "\nif(CORBA_is_nil(_ob_clt_))";
	    out.inc();
	    out << "\nthrow CORBA_NO_IMPLEMENT();";
	    out.dec();
	    out.sep();
	    out << "\nCORBA_ULong _ob_off = _ob_clt_ -> "
		<< "offset(this, \"_get_" << desc -> name << "\");";
	    out.sep();
	    out << "\nOBBuffer _ob_buf(_ob_off);";
	    out.sep();
	    out << "\nbool _ob_sw, _ob_ex, _ob_fo;";
	    out << "\n_ob_off = _ob_clt_ -> request(this, \"_get_"
		<< desc -> name
		<< "\", _ob_buf, _ob_sw, _ob_ex, _ob_fo, "
		<< "_ob_tout_, _ob_retry_);";
	    out.sep();
	    out << "\nconst CORBA_Octet* _ob_co = _ob_buf.data + _ob_off;";
	    out.sep();
	    out << "\nif(_ob_fo)";
	    out.start();
	    out << "\n_OB_forward(_ob_co, _ob_sw);";
	    out << "\nreturn " << name << "();";
	    out.end();
	    out.sep();
	    out << "\nif(_ob_ex)";
	    out.inc();
	    out << "\nthrow CORBA_UNKNOWN();";
	    out.dec();
	    out.sep();
	    writeReturnUnmarshalCode(scope, desc -> type, out);
	    out << "\nreturn _ob_r;";
	    out.end();

	    if(desc -> mode == CORBA_ATTR_NORMAL)
	    {
		CORBA_String_var in = getTypeString(scope, desc -> type,
						    GetTypeIn, false);
		out.sep();
		out << "\nvoid\n" << absolute << '(' << in
		    << " _ob_a)";
		out.start();
		out << "\nif(CORBA_is_nil(_ob_clt_))";
		out.inc();
		out << "\nthrow CORBA_NO_IMPLEMENT();";
		out.dec();
		out.sep();
		out << "\nCORBA_ULong _ob_off = _ob_clt_ -> "
		    << "offset(this, \"_set_" << desc -> name << "\");";
		out << "\nCORBA_ULong _ob_cnt = _ob_off;";
		writeMarshalCountCode(desc -> type, false,
				      "_ob_a", "_ob_cnt", out);
		out.sep();
		out << "\nOBBuffer _ob_buf(_ob_cnt);";
		out << "\nCORBA_Octet* _ob_o = _ob_buf.data + _ob_off;";
		writeMarshalCode(desc -> type, false, "_ob_a", "_ob_o", out);
		out.sep();
		out << "\nbool _ob_sw, _ob_ex, _ob_fo;";
		out << "\n_ob_clt_ -> request(this, \"_set_" << desc -> name
		    << "\", _ob_buf, _ob_sw, _ob_ex, _ob_fo, "
		    << "_ob_tout_, _ob_retry_);";
		out.sep();
		out << "\nif(_ob_fo)";
		out.start();
		out << "\nconst CORBA_Octet* _ob_co = _ob_buf.data + _ob_off;";
		out << "\n_OB_forward(_ob_co, _ob_sw);";
		out << '\n' << name << "(_ob_a);";
		out << "\nreturn;";
		out.end();
		out.sep();
		out << "\nif(_ob_ex)";
		out.inc();
		out << "\nthrow CORBA_UNKNOWN();";
		out.dec();
		out.end();
	    }

	    break;
	}

	case CORBA_dk_Operation:
	{
	    //
	    // Operation
	    //
	    if(local_)
		continue;

	    CORBA_OperationDescription* desc;
	    CORBA_Boolean b = seq[i].value >>= desc;
	    assert(b);

	    if(!check(desc -> id))
		continue;

	    CORBA_Identifier_var name = fixKwd(desc -> name);
	    CORBA_ScopedName_var absolute = getAbsolute(desc -> id);
	    
	    comment(desc -> id, out);

	    CORBA_String_var ret =
		getTypeString("", desc -> result, GetTypeReturn);
	    
	    out.sep();
	    out << '\n' << ret << '\n' << absolute << "(";
	    
	    unsigned int indent = out.getIndent();
	    out.setIndent(out.getPos());

	    for(j = 0 ; j < desc -> parameters.length() ; j++)
	    {
		GetType tt;
		switch(desc -> parameters[j].mode)
		{
		case CORBA_PARAM_IN:
		    tt = GetTypeIn;
		    break;

		case CORBA_PARAM_INOUT:
		    tt = GetTypeInOut;
		    break;

		case CORBA_PARAM_OUT:
		    tt = GetTypeOut;
		    break;
		}

		CORBA_String_var arg = CORBA_string_dup("_ob_a");
		arg += j;

		CORBA_String_var str =
		    getTypeString(scope, desc -> parameters[j].type, tt,
				  false, arg);

		if(j > 0)
		    out << ",\n";

		out << str;
	    }

	    if(desc -> contexts.length() > 0)
	    {
		if(desc -> parameters.length() > 0)
		    out << ",\n";
		
		out << "CORBA_Context_ptr _ob_ctx";
	    }

	    out << ")";

	    out.setIndent(indent);
	    out.start();
	    out << "\nif(CORBA_is_nil(_ob_clt_))";
	    out.inc();
	    out << "\nthrow CORBA_NO_IMPLEMENT();";
	    out.dec();

	    out.sep();
	    out << "\nCORBA_ULong _ob_off = _ob_clt_ -> offset(this, \""
		<< desc -> name << "\");";
	    out << "\nCORBA_ULong _ob_cnt = _ob_off;";
	    bool needMarshal = false;
	    for(j = 0 ; j < desc -> parameters.length() ; j++)
	    {
		if(desc -> parameters[j].mode != CORBA_PARAM_OUT)
		{
		    CORBA_TypeCode_ptr argType = desc -> parameters[j].type;
		    CORBA_String_var arg = CORBA_string_dup("_ob_a");
		    arg += j;
		    writeMarshalCountCode(argType, false, arg, "_ob_cnt", out);
		    needMarshal = true;
		}
	    }
	    if(desc -> contexts.length() > 0)
	    {
		out << "\nOBStrSeq _ob_ctxSeq;";
		for(j = 0 ; j < desc -> contexts.length() ; j++)
		{
		    out << "\n_ob_ctx -> _OB_getValues(\"\", 0, \""
			<< desc -> contexts[j] << "\", _ob_ctxSeq);";
		}
		out << "\nOBMarshalCount(_ob_ctxSeq, _ob_cnt);";
		needMarshal = true;
	    }

	    out.sep();
	    out << "\nOBBuffer _ob_buf(_ob_cnt);";
	    if(needMarshal)
	    {
		out << "\nCORBA_Octet* _ob_o = _ob_buf.data + _ob_off;";
	    }
	    for(j = 0 ; j < desc -> parameters.length() ; j++)
	    {
		if(desc -> parameters[j].mode != CORBA_PARAM_OUT)
		{
		    CORBA_TypeCode_ptr argType = desc -> parameters[j].type;
		    CORBA_String_var arg = CORBA_string_dup("_ob_a");
		    arg += j;
		    writeMarshalCode(argType, false, arg, "_ob_o", out);
		}
	    }
	    if(desc -> contexts.length() > 0)
	    {
		out << "\nOBMarshal(_ob_ctxSeq, _ob_o);";
	    }

	    out.sep();
	    if(desc -> mode == CORBA_OP_ONEWAY)
	    {
		out << "\n_ob_clt_ -> oneway(this, \"" << desc -> name
		    << "\", _ob_buf, _ob_retry_);";
	    }
	    else
	    {
		out << "\nbool _ob_sw, _ob_ex, _ob_fo;";
		out << "\n_ob_off = _ob_clt_ -> request(this, \""
		    << desc -> name << "\", _ob_buf, _ob_sw, "
		    << "_ob_ex, _ob_fo, _ob_tout_, _ob_retry_);";

		CORBA_TypeCode_var origRet = OBGetOrigType(desc -> result);
		bool needUnmarshal = origRet -> kind() != CORBA_tk_void;
		if(needUnmarshal == false)
		{
		    for(j = 0 ; j < desc -> parameters.length() ; j++)
		    {
			if(desc -> parameters[j].mode == CORBA_PARAM_OUT ||
			   desc -> parameters[j].mode == CORBA_PARAM_INOUT)
			{
			    needUnmarshal = true;
			    break;
			}
		    }
		}

		if(needUnmarshal || desc -> exceptions.length() > 0)
		{
		    out.sep();
		    out << "\nconst CORBA_Octet* _ob_co = "
			<< "_ob_buf.data + _ob_off;";
		}

		out.sep();
		out << "\nif(_ob_fo)";
		out.start();
		if(!(needUnmarshal || desc -> exceptions.length() > 0))
		{
		    out << "\nconst CORBA_Octet* _ob_co = "
			<< "_ob_buf.data + _ob_off;";
		}
		out << "\n_OB_forward(_ob_co, _ob_sw);";
		if(origRet -> kind() != CORBA_tk_void)
		    out << "\nreturn " << name << '(';
		else
		    out << '\n' << name << '(';
		for(j = 0 ; j < desc -> parameters.length() ; j++)
		{
		    if(j > 0)
			out << ", ";
		    out << "_ob_a" << j;
		}
		if(desc -> contexts.length() > 0)
		{
		    if(desc -> parameters.length() > 0)
			out << ", ";
		    out << "_ob_ctx";
		}
		out << ");";
		if(origRet -> kind() == CORBA_tk_void)
		    out << "\nreturn;";
		out.end();

		out.sep();
		out << "\nif(_ob_ex)";
		if(desc -> exceptions.length() > 0)
		    out.start();
		else
		    out.inc();
		for(j = 0 ; j < desc -> exceptions.length() ; j++)
		{
		    if(j == 0)
		    {
			out << "\nCORBA_String_var _ob_id;";
			out << "\nconst CORBA_Octet* _ob_coid = _ob_co;";
			out << "\nOBUnmarshal(_ob_id.inout(), "
			    << "_ob_coid, _ob_sw);";
			out.sep();
			out << '\n';
		    }
		    else
			out << "\nelse ";

		    out << "if(strcmp(_ob_id, \""
			<< desc -> exceptions[j].id << "\") == 0)";
		    out.start();
		    CORBA_TypeCode_ptr exType = desc -> exceptions[j].type;
		    CORBA_String_var s = getTypeString(scope, exType,
						       GetTypeNormal);
		    out << '\n' << s << " _ob_except;";
		    out << "\nOBUnmarshal(_ob_except, _ob_co, _ob_sw);";
		    out.sep();
		    out << "\nthrow _ob_except;";
		    out.end();
		}
		if(desc -> exceptions.length() > 0)
		{
		    out << "\nelse";
		    out.inc();
		}
		out << "\nthrow CORBA_UNKNOWN();";
		if(desc -> exceptions.length() > 0)
		{
		    out.dec();
		    out.end();
		}
		else
		    out.dec();

		if(needUnmarshal)
		{
		    out.sep();
		    writeReturnUnmarshalCode(scope, desc -> result, out);
		    for(j = 0 ; j < desc -> parameters.length() ; j++)
		    {
			CORBA_TypeCode_ptr argType =
			    desc -> parameters[j].type;
			
			if(desc -> parameters[j].mode == CORBA_PARAM_OUT)
			{
			    writeOutUnmarshalCode(scope, argType, out, j);
			}
			else if(desc -> parameters[j].mode ==
				CORBA_PARAM_INOUT)
			{
 			    CORBA_String_var arg = CORBA_string_dup("_ob_a");
 			    arg += j;
 			    writeUnmarshalCode(argType, false, arg,
 					       "_ob_co", "_ob_sw", out);
			}
		    }
		    if(origRet -> kind() != CORBA_tk_void)
			out << "\nreturn _ob_r;";
		}
	    }
	    out.end();

	    break;
	}


	default:
	    break;
	}

	//
	// Check for recursion
	//
	CORBA_Container_var cont =
	    CORBA_Container::_narrow(seq[i].contained_object);
	if(!CORBA_is_nil(cont))
	    genCPlusPlusC(cont, out);
    }
}

// ----------------------------------------------------------------------
// Generate code for the source file, anonymous types part
// ----------------------------------------------------------------------

void
IdlCPPGenerator::genCPlusPlusCAnonTypes(IdlPrettyPrint& out, const char* macro)
{
    CORBA_ULong i;

    for(i = 0 ; i < anonTCSeq_.length() ; i++)
    {
	CORBA_TypeCode_var type = OBGetOrigType(anonTCSeq_[i]);

	//
	// Sequences
	//
	if(type -> kind() == CORBA_tk_sequence)
	{
	    //
	    // Get unaliased content type
	    //
	    CORBA_TypeCode_var contentType = type -> content_type();
	    contentType = OBGetOrigType(contentType);
	    
	    //
	    // Get absolute name
	    //
	    CORBA_ScopedName_var absolute =
		getTypeString("", type, GetTypeNormal, true);

	    comment(absolute, out);
	    
	    CORBA_String_var anon = IdlGetAnonName(absolute);
	    out.sep();
	    out.direct("\n#ifdef ");
	    out << "OB_use_" << anon << "_from_" << macro;

	    if(!isInLibrary(type))
	    {
		out.sep();
		out.direct("\n#ifndef HAVE_NO_EXPLICIT_TEMPLATES");
		out << "\ntemplate class " << absolute << ';';
		out << "\ntemplate class OBSeqVar< " << absolute << " >;";
		out.direct("\n#else");
		out.direct("\n#ifdef HAVE_PRAGMA_DEFINE");
		out << "\n#pragma define(" << absolute << ')';
		out << "\n#pragma define(OBSeqVar< " << absolute << " >)";
		out.direct("\n#endif"); // HAVE_PRAGMA_DEFINE
		out.direct("\n#endif"); // HAVE_NO_EXPLICIT_TEMPLATES
		    
		if(!local_)
		{
		    //
		    // CDR functions
		    //
		    CORBA_TCKind k = contentType -> kind();
		    
		    if(k == CORBA_tk_short || k == CORBA_tk_long ||
		       k == CORBA_tk_ushort || k == CORBA_tk_ulong ||
		       k == CORBA_tk_float || k == CORBA_tk_double ||
		       k == CORBA_tk_boolean || k == CORBA_tk_char ||
		       k == CORBA_tk_octet)
		    {
			out.sep();
			out << "\nvoid\nOBMarshal(const "
			    << absolute << "& seq, CORBA_Octet*& oct)";
			out.start();
			out << "\nOBMarshal(seq.length(), oct);";
			out << "\nOBMarshalMulti(seq.data(), oct, "
			    << "seq.length());";
			out.end();
			
			out.sep();
			out << "\nvoid\nOBMarshalCount(const " << absolute
			    << "& seq, CORBA_ULong& count)";
			out.start();
			out << "\nOBMarshalCount(seq.length(), count);";
			out << "\nOBMarshalCountMulti(seq.data(), count, "
			    << "seq.length());";
			out.end();
			
			out.sep();
			out << "\nvoid\nOBUnmarshal(" << absolute
			    << "& seq, const CORBA_Octet*& coct, bool swap)";
			out.start();
			out << "\nCORBA_ULong len;";
			out << "\nOBUnmarshal(len, coct, swap);";
			out << "\nseq.length(len);";
			out << "\nOBUnmarshalMulti(seq.data(), coct, swap, "
			    << "len);";
			out.end();
		    }
		    else
		    {
			CORBA_String_var arg = CORBA_string_dup("seq[i]");
			
			out.sep();
			out << "\nvoid\nOBMarshal(const "
			    << absolute << "& seq, CORBA_Octet*& oct)";
			out.start();
			out << "\nOBMarshal(seq.length(), oct);";
			out << "\nfor(CORBA_ULong i = 0 ; i < seq.length() ; "
			    << "i++)";
			out.inc();
			writeMarshalCode(contentType, false, arg, "oct", out);
			out.dec();
			out.end();
			
			out.sep();
			out << "\nvoid\nOBMarshalCount(const "
			    << absolute << "& seq, CORBA_ULong& count)";
			out.start();
			out << "\nOBMarshalCount(seq.length(), count);";
			out << "\nfor(CORBA_ULong i = 0 ; i < seq.length() ; "
			    << "i++)";
			out.inc();
			writeMarshalCountCode(contentType, false, arg, "count",
					      out);
			out.dec();
			out.end();
			
			out.sep();
			out << "\nvoid\nOBUnmarshal(" << absolute
			    << "& seq, const CORBA_Octet*& coct, bool swap)";
			out.start();
			out << "\nCORBA_ULong len;";
			out << "\nOBUnmarshal(len, coct, swap);";
			out << "\nseq.length(len);";
			out << "\nfor(CORBA_ULong i = 0 ; i < len ; i++)";
			out.inc();
			writeUnmarshalCode(contentType, true, arg, "coct",
					   "swap", out);
			out.dec();
			out.end();
		    }
		}
	    }
	    
	    if(!noTC_)
	    {
		//
		// TypeCode constant
		//
		out.sep();
		out << "\nstatic OBTypeCodeConst _tc_" << anon << '(';
		IdlOutputAsciiTypeCode(type, out);
		out << ");";
		
		//
		// Any insertion and extraction
		//
		out.sep();
		out.direct("\n#ifndef HAVE_NO_EXPLICIT_TEMPLATES");
		out << "\ntemplate class OBInfo< " << absolute << " >;";
		out.direct("\n#else");
		out.direct("\n#ifdef HAVE_PRAGMA_DEFINE");
		out << "\n#pragma define(OBInfo< " << absolute << " >)";
		out.direct("\n#endif"); // HAVE_PRAGMA_DEFINE
		out.direct("\n#endif"); // HAVE_NO_EXPLICIT_TEMPLATES
		out.sep();
		out << "\nvoid\noperator<<=(CORBA_Any& any, " << absolute
		    << "* p)";
		out.start();
		out << "\nstatic const OBInfo< " << absolute << " > info;";
		out << "\nany.replace(_tc_" << anon << ", p, true, &info);";
		out.end();
		
		out.sep();
		out << "\nvoid\noperator<<=(CORBA_Any& any, const " << absolute
		    << "& seq)";
		out.start();
		out << "\nstatic const OBInfo< " << absolute << " > info;";
		out << '\n' << absolute << "* p = new " << absolute
		    << "(seq);";
		out << "\nany.replace(_tc_" << anon << ", p, true, &info);";
		out.end();
		
		out.sep();
		out << "\nCORBA_Boolean\noperator>>=(const CORBA_Any& any, "
		    << absolute << "*& p)";
		out.start();
		out << "\nif(any.check_type(_tc_" << anon << "))";
		out.start();
		out << "\nif(!any.info())";
		out.start();
		out << "\nconst OBBuffer* cbufp = "
		    << "(const OBBuffer*)any.value();";
		out << "\nconst CORBA_Octet* coct = cbufp -> data;";
		out << '\n' << absolute << "* v = new " << absolute << ';';
		out << "\nOBUnmarshal(*v, coct, false);";
		out << "\n(CORBA_Any&)any <<= v;";
		out.end();
		out.sep();
		out << "\np = (" << absolute << "*)any.value();";
		out << "\nreturn true;";
		out.end();
		out << "\nelse";
		out.inc();
		out << "\nreturn false;";
		out.dec();
		out.end();
	    }
	    
	    out.sep();
	    out.direct("\n#endif"); // OB_use_...
	}
	
	//
	// Arrays
	//
	if(type -> kind() == CORBA_tk_array)
	{
	    //
	    // Get absolute name
	    // Get absolute forany
	    //
	    CORBA_ScopedName_var absolute =
		getTypeString("", type, GetTypeNormal, true);
	    CORBA_ScopedName_var forAny =
		getTypeString("", type, GetTypeForAny, true);

	    //
	    // Get absolute content type
	    //
	    CORBA_TypeCode_var contentType;
	    CORBA_ULong length;
	    getArrayType(type, contentType.out(), length);
	    CORBA_String_var cont = getTypeString("", contentType,
						  GetTypeArray, true);

	    comment(absolute, out);
	    
	    CORBA_String_var anon = IdlGetAnonName(absolute);
	    out.sep();
	    out.direct("\n#ifdef ");
	    out << "OB_use_" << anon << "_from_" << macro;

	    bool variable = IdlIsVariable(type);

	    //
	    // _var type
	    //
	    out.sep();
	    out.direct("\n#ifndef HAVE_NO_EXPLICIT_TEMPLATES");
	    if(variable)
	    {
		out << "\ntemplate class OBVarArrayVar< OBSlice_" << anon
		    << ", " << cont << ", " << length << " >;";
		out << "\ntemplate class OBVarArrayForAny< OBSlice_" << anon
		    << ", " << cont << ", " << length << " >;";
	    }
	    else
	    {
		out << "\ntemplate class OBFixArrayVar< OBSlice_" << anon
		    << ", " << cont << ", " << length << " >;";
		out << "\ntemplate class OBFixArrayForAny< OBSlice_" << anon
		    << ", " << cont << ", " << length << " >;";
	    }
	    out.direct("\n#else");
	    out.direct("\n#ifdef HAVE_PRAGMA_DEFINE");
	    if(variable)
	    {
		out << "\n#pragma define(OBVarArrayVar< OBSlice_" << anon
		    << ", " << cont << ", " << length << " >)";
		out << "\n#pragma define(OBVarArrayForAny< OBSlice_" << anon
		    << ", " << cont << ", " << length << " >)";
	    }
	    else
	    {
		out << "\n#pragma define(OBFixArrayVar< OBSlice_" << anon
		    << ", " << cont << ", " << length << " >)";
		out << "\n#pragma define(OBFixArrayForAny< OBSlice_" << anon
		    << ", " << cont << ", " << length << " >)";
	    }
	    out.direct("\n#endif"); // HAVE_PRAGMA_DEFINE
	    out.direct("\n#endif"); // HAVE_NO_EXPLICIT_TEMPLATES

	    if(!local_)
	    {
		//
		// CDR functions
		//
		CORBA_TCKind k = contentType -> kind();
		if(k == CORBA_tk_short || k == CORBA_tk_long ||
		   k == CORBA_tk_ushort || k == CORBA_tk_ulong ||
		   k == CORBA_tk_float || k == CORBA_tk_double ||
		   k == CORBA_tk_boolean || k == CORBA_tk_char ||
		   k == CORBA_tk_octet)
		{
		    out.sep();
		    out << "\nvoid\nOBMarshal_" << anon << "(const OBSlice_"
			<< anon << "* s, CORBA_Octet*& oct)";
		    out.start();
		    out << "\nOBMarshalMulti(";
		    if(length != type -> length())
			out << '(' << cont << "*)";
		    out << "s, oct, " << length << ");";
		    out.end();
		    
		    out.sep();
		    out << "\nvoid\nOBMarshalCount_" << anon
			<< "(const OBSlice_" << anon
			<< "* s, CORBA_ULong& count)";
		    out.start();
		    out << "\nOBMarshalCountMulti(";
		    if(length != type -> length())
			out << '(' << cont << "*)";
		    out << "s, count, " << length << ");";
		    out.end();
		    
		    out.sep();
		    out << "\nvoid\nOBUnmarshal_" << anon << "(OBSlice_"
			<< anon << "* s, const CORBA_Octet*& coct, bool swap)";
		    out.start();
		    out << "\nOBUnmarshalMulti(";
		    if(length != type -> length())
			out << '(' << cont << "*)";
		    out << "s, coct, swap, " << length << ");";
		    out.end();
		}
		else
		{
		    CORBA_String_var arg;
		    if(length != type -> length())
		    {
			arg = CORBA_string_dup("((");
			arg += cont;
			arg += "*)s)[i]";
		    }
		    else
		    {
			arg = CORBA_string_dup("s[i]");
		    }
		    
		    out.sep();
		    out << "\nvoid\nOBMarshal_" << anon << "(const OBSlice_"
			<< anon << "* s, CORBA_Octet*& oct)";
		    out.start();
		    out << "\nfor(CORBA_ULong i = 0 ; i < " << length
			<< " ; i++)";
		    out.inc();
		    writeMarshalCode(contentType, true, arg, "oct", out);
		    out.dec();
		    out.end();
		    
		    out.sep();
		    out << "\nvoid\nOBMarshalCount_" << anon
			<< "(const OBSlice_" << anon
			<< "* s, CORBA_ULong& count)";
		    out.start();
		    out << "\nfor(CORBA_ULong i = 0 ; i < " << length
			<< " ; i++)";
		    out.inc();
		    writeMarshalCountCode(contentType, true, arg, "count",
					  out);
		    out.dec();
		    out.end();
		    
		    out.sep();
		    out << "\nvoid\nOBUnmarshal_" << anon << "(OBSlice_"
			<< anon	<< "* s, const CORBA_Octet*& coct, bool swap)";
		    out.start();
		    out << "\nfor(CORBA_ULong i = 0 ; i < " << length
			<< " ; i++)";
		    out.inc();
		    writeUnmarshalCode(contentType, true, arg, "coct", "swap",
				       out);
		    out.dec();
		    out.end();
		}
	    }
		
	    //
	    // alloc, dup, copy, free
	    //
	    out.sep();
	    out << "\nOBSlice_" << anon << '*';
	    out << "\nOBAlloc_" << anon << "()";
	    out.start();
	    out << "\nreturn ";
	    if(length != type -> length())
		out << "(OBSlice_" << anon << "*) ";
	    out << "new " << cont << '[' << length << "];";
	    out.end();
	    
	    out.sep();
	    out << "\nOBSlice_" << anon << '*';
	    out << "\nOBDup_" << anon << "(const OBSlice_" << anon << "* s)";
	    out.start();
	    out << "\nOBSlice_" << anon << "* to = ";
	    if(length != type -> length())
		out << "(OBSlice_" << anon << "*) ";
	    out << "new " << cont << '[' << length << "];";
	    if(variable)
	    {
		out << "\nfor(CORBA_ULong i = 0 ; i < " << length << " ; i++)";
		out.inc();
		if(length != type -> length())
		    out << "\n((" << cont << "*)to)[i] = "
			<< "((" << cont << "*)s)[i];";
		else
		    out << "\nto[i] = s[i];";
		out.dec();
	    }
	    else
	    {
		out << "\nmemcpy(to, s, " << length
		    << " * sizeof(" << cont << "));";
	    }
	    out << "\nreturn to;";
	    out.end();
	    
	    out.sep();
	    out << "\nvoid";
	    out << "\nOBCopy_" << anon << "(const OBSlice_"
		<< anon << "* s, OBSlice_" << anon << "* to)";
	    out.start();
	    if(variable)
	    {
		out << "\nfor(CORBA_ULong i = 0 ; i < " << length << " ; i++)";
		out.inc();
		if(length != type -> length())
		    out << "\n((" << cont << "*)to)[i] = "
			<< "((" << cont << "*)s)[i];";
		else
		    out << "\nto[i] = s[i];";
		out.dec();
	    }
	    else
	    {
		out << "\nmemcpy(to, s, " << length
		    << " * sizeof(" << cont << "));";
	    }
	    out.end();
	    
	    out.sep();
	    out << "\nvoid";
	    out << "\nOBFree_" << anon << "(OBSlice_" << anon << "* s)";
	    out.start();
	    out << "\ndelete [] ";
	    if(length != type -> length())
		out << '(' << cont << "*)";
	    out << "s;";
	    out.end();

	    if(!noTC_)
	    {
		//
		// TypeCode constant
		//
		out.sep();
		out << "\nstatic OBTypeCodeConst _tc_" << anon << '(';
		IdlOutputAsciiTypeCode(type, out);
		out << ");";
		
		//
		// Any insertion and extraction
		//
		out.sep();
		out << "\nstruct OBInfo_" << anon
		    << " : public OBConstructedInfo";
		out.start();

		out << "\nOBInfo_" << anon << "() { };";

		out.sep();
		out << "\nvirtual void* alloc() const";
		out.start();
		out << "\nreturn OBAlloc_" << anon << "();";
		out.end();

		out.sep();
		out << "\nvirtual void free(void* p) const";
		out.start();
		out << "\nOBFree_" << anon << "((OBSlice_"
		    << anon << "*)p);";
		out.end();

		out.sep();
		out << "\nvirtual void* dup(const void* p) const";
		out.start();
		out << "\nreturn OBDup_" << anon << "((const OBSlice_"
		    << anon << "*)p);";
		out.end();

		out.sep();
		out << "\nvirtual void marshal(const void* p, "
		    << "CORBA_Octet*& oct) const";
		out.start();
		out << "\nOBMarshal_" << anon << "((const OBSlice_"
		    << anon << "*)p, oct);";
		out.end();

		out.sep();
		out << "\nvirtual void marshalCount(const void* p, "
		    << "CORBA_ULong& count) const";
		out.start();
		out << "\nOBMarshalCount_" << anon << "((const OBSlice_"
		    << anon << "*)p, count);";
		out.end();

		out.sep();
		out << "\nvirtual void unmarshal(void* p, "
		    << "const CORBA_Octet*& coct, bool swap) const";
		out.start();
		out << "\nOBUnmarshal_" << anon << "((OBSlice_"
		    << anon << "*)p, coct, swap);";
		out.end();
		out.end();
		out << ';';

		out.sep();
		out << "\nvoid\noperator<<=(CORBA_Any& any, const " << forAny
		    << "& r)";
		out.start();
		out << "\nconst OBSlice_" << anon << "* s;";
		out.sep();
		out << "\nif(r.nocopy())";
		out.inc();
		out << "\ns = r.in();";
		out.dec();
		out << "\nelse";
		out.inc();
		out.direct("\n#ifdef HAVE_VCPLUSPLUS_BUGS");
		out << "\ns = (const OBSlice_" << anon << "*)OBDup_"
		    << anon << "(r.in());";
		out.direct("\n#else");
		out << "\ns = OBDup_" << anon << "(r);";
		out.direct("\n#endif"); // HAVE_VCPLUSPLUS_BUGS
		out.dec();
		out.sep();
		out << "\nstatic const OBInfo_" << anon << " info;";
		out << "\nany.replace(_tc_" << anon << ", (void*)s, "
		    << "true, &info);";
		out.end();
		
		out.sep();
		out << "\nCORBA_Boolean\noperator>>=(const CORBA_Any& any, "
		    << forAny << "& r)";
		out.start();
		out << "\nif(any.check_type(_tc_" << anon << "))";
		out.start();
		out << "\nif(!any.info())";
		out.start();
		out << "\nconst OBBuffer* cbufp = "
		    << "(const OBBuffer*)any.value();";
		out << "\nconst CORBA_Octet* coct = cbufp -> data;";
		out << "\nOBSlice_" << anon << "* s = OBAlloc_" << anon
		    << "();";
		out << "\nOBUnmarshal_" << anon << "(s, coct, false);";
		out << "\n(CORBA_Any&)any <<= " << forAny << "(s, true);";
		out.end();
		out.sep();
		out << "\nr = (OBSlice_" << anon << "*)any.value();";
		out << "\nreturn true;";
		out.end();
		out << "\nelse";
		out.inc();
		out << "\nreturn false;";
		out.dec();
		out.end();
	    }
		
	    out.sep();
	    out.direct("\n#endif"); // OB_use_...
	}
    }
}
