// **********************************************************************
//
// 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>

#ifdef HAVE_FSTREAM
#   include <fstream>
#else
#   include <fstream.h>
#endif

#include <GenRTF.h>

#ifdef HAVE_NO_STRCASECMP
#   define strcasecmp stricmp
#else
#   ifdef HAVE_STRINGS_H
#       include <strings.h> // On some platforms, strcasecmp is strings.h
#   endif
#endif

//
// The top-level file name (without ".rtf")
//
const char* IdlRTFGenerator::top_ = "_top_";

const char* IdlRTFGenerator::boldon_ = "\\b ";
const char* IdlRTFGenerator::boldoff_ = "\\b0 ";

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

int
IdlRTFGenerator::genRTF(CORBA_Container_ptr container, IdlPrettyPrint& out)
{
    //
    // Get scope
    //
    CORBA_String_var scope;
    getScope(container, scope.out());

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

    CORBA_ULong i, j, k;

    //
    // Create name and description list
    //
    IdlStringSeq nameSeq;
    CORBA_Container::DescriptionSeq seq;
    for(i = 0; i < allSeq -> length() ; i++)
    {
	const char* name;

	switch(allSeq[i].kind)
	{
	case CORBA_dk_Attribute:
	{
	    CORBA_AttributeDescription* desc;
	    CORBA_Boolean b = allSeq[i].value >>= desc;
	    assert(b);
	    name = desc -> name;
	    break;
	}

	case CORBA_dk_Constant:
	{
	    CORBA_ConstantDescription* desc;
	    CORBA_Boolean b = allSeq[i].value >>= desc;
	    assert(b);
	    name = desc -> name;
	    break;
	}

	case CORBA_dk_Exception:
	{
	    CORBA_ExceptionDescription* desc;
	    CORBA_Boolean b = allSeq[i].value >>= desc;
	    assert(b);
	    name = desc -> name;
	    break;
	}

	case CORBA_dk_Interface:
	{
	    CORBA_InterfaceDescription* desc;
	    CORBA_Boolean b = allSeq[i].value >>= desc;
	    assert(b);
	    name = desc -> name;
	    break;
	}

	case CORBA_dk_Module:
	{
	    CORBA_ModuleDescription* desc;
	    CORBA_Boolean b = allSeq[i].value >>= desc;
	    assert(b);
	    name = desc -> name;
	    break;
	}

	case CORBA_dk_Operation:
	{
	    CORBA_OperationDescription* desc;
	    CORBA_Boolean b = allSeq[i].value >>= desc;
	    assert(b);
	    name = desc -> name;
	    break;
	}

	case CORBA_dk_Typedef:
	case CORBA_dk_Alias:
	case CORBA_dk_Struct:
	case CORBA_dk_Union:
	case CORBA_dk_Enum:
	{
	    CORBA_TypeDescription* desc;
	    CORBA_Boolean b = allSeq[i].value >>= desc;
	    assert(b);
	    name = desc -> name;
	    break;
	}

	default:
	    continue;
	}

	seq.append(allSeq[i]);
	nameSeq.append(name);
    }

    //
    // Sort name and description lists (bubblesort)
    //
    if(!noSort_)
    {
	for(i = 0 ; i < nameSeq.length() ; i++)
	{
	    for(j = i ; j < nameSeq.length() ; j++)
	    {
		if(!ignoreCase_)
		{
		    if(strcmp(nameSeq[i], nameSeq[j]) > 0)
		    {
			CORBA_String_var name = nameSeq[i]._retn();
			nameSeq[i] = nameSeq[j]._retn();
			nameSeq[j] = name._retn();

			CORBA_Container::Description desc = seq[i];
			seq[i] = seq[j];
			seq[j] = desc;
		    }
		}
		else
		{
		    if(strcasecmp(nameSeq[i], nameSeq[j]) > 0)
		    {
			CORBA_String_var name = nameSeq[i]._retn();
			nameSeq[i] = nameSeq[j]._retn();
			nameSeq[j] = name._retn();
			
			CORBA_Container::Description desc = seq[i];
			seq[i] = seq[j];
			seq[j] = desc;
		    }
		}
	    }
	}
    }

    bool first;

    // ------------------------------------------------------------
    // Pass 1: Index generation
    // ------------------------------------------------------------

    if(withIndex_)
    {
	out << '\n';

	//
	// Alias index
	//
	first = true;
	for(i = 0 ; i < seq.length() ; i++)
	{
	    if(seq[i].kind == CORBA_dk_Alias)
	    {
		CORBA_TypeDescription* desc;
		CORBA_Boolean b = seq[i].value >>= desc;
		assert(b);

		if(first)
		{
		    out << '\n' << heading_ << "Alias Index" << body_ << '\n';
		    first = false;
		}

		intro(desc -> id, desc -> name, out);
	    }
	}
	if(!first)
	    out << '\n';

	//
	// Constant index
	//
	first = true;
	for(i = 0 ; i < seq.length() ; i++)
	{
	    if(seq[i].kind == CORBA_dk_Constant)
	    {
		CORBA_ConstantDescription* desc;
		CORBA_Boolean b = seq[i].value >>= desc;
		assert(b);

		if(first)
		{
		    out << '\n' << heading_ << "Constant Index" << body_
			<< '\n';
		    first = false;
		}

		intro(desc -> id, desc -> name, out);
	    }
	}
	if(!first)
	    out << '\n';

	//
	// Exception index
	//
	first = true;
	for(i = 0 ; i < seq.length() ; i++)
	{
	    if(seq[i].kind == CORBA_dk_Exception)
	    {
		CORBA_ExceptionDescription* desc;
		CORBA_Boolean b = seq[i].value >>= desc;
		assert(b);
	    
		if(first)
		{
		    out << '\n' << heading_ << "Exception Index" << body_
			<< '\n';
		    first = false;
		}

		intro(desc -> id, desc -> name, out);
	    }
	}
	if(!first)
	    out << '\n';

	//
	// Struct index
	//
	first = true;
	for(i = 0 ; i < seq.length() ; i++)
	{
	    if(seq[i].kind == CORBA_dk_Struct)
	    {
		CORBA_TypeDescription* desc;
		CORBA_Boolean b = seq[i].value >>= desc;
		assert(b);

		if(first)
		{
		    out << '\n' << heading_ << "Struct Index" << body_ << '\n';
		    first = false;
		}
		
		intro(desc -> id, desc -> name, out);
	    }
	}
	if(!first)
	    out << '\n';

	//
	// Union index
	//
	first = true;
	for(i = 0 ; i < seq.length() ; i++)
	{
	    if(seq[i].kind == CORBA_dk_Union)
	    {
		CORBA_TypeDescription* desc;
		CORBA_Boolean b = seq[i].value >>= desc;
		assert(b);

		if(first)
		{
		    out << '\n' << heading_ << "Union Index" << body_ << '\n';
		    first = false;
		}

		intro(desc -> id, desc -> name, out);
	    }
	}
	if(!first)
	    out << '\n';

	//
	// Enum index
	//
	first = true;
	for(i = 0 ; i < seq.length() ; i++)
	{
	    if(seq[i].kind == CORBA_dk_Enum)
	    {
		CORBA_TypeDescription* desc;
		CORBA_Boolean b = seq[i].value >>= desc;
		assert(b);

		if(first)
		{
		    out << '\n' << heading_ << "Enum Index" << body_ << '\n';
		    first = false;
		}

		intro(desc -> id, desc -> name, out);
	    }
	}
	if(!first)
	    out << '\n';

	//
	// Attribute index
	//
	first = true;
	for(i = 0 ; i < seq.length() ; i++)
	{
	    if(seq[i].kind == CORBA_dk_Attribute)
	    {
		CORBA_AttributeDescription* desc;
		CORBA_Boolean b = seq[i].value >>= desc;
		assert(b);

		if(first)
		{
		    out << '\n' << heading_ << "Attribute Index" << body_
			<< '\n';
		    first = false;
		}

		intro(desc -> id, desc -> name, out);
	    }
	}
	if(!first)
	    out << '\n';

	//
	// Operation index
	//
	first = true;
	for(i = 0 ; i < seq.length() ; i++)
	{
	    if(seq[i].kind == CORBA_dk_Operation)
	    {
		CORBA_OperationDescription* desc;
		CORBA_Boolean b = seq[i].value >>= desc;
		assert(b);
	    
		if(first)
		{
		    out << '\n' << heading_ << "Operation Index" << body_
			<< '\n';
		    first = false;
		}

		intro(desc -> id, desc -> name, out);
	    }
	}
	if(!first)
	    out << '\n';
	//
	// Module index
	//
	first = true;
	for(i = 0 ; i < seq.length() ; i++)
	{
	    if(seq[i].kind == CORBA_dk_Module)
	    {
		CORBA_ModuleDescription* desc;
		CORBA_Boolean b = seq[i].value >>= desc;
		assert(b);

		if(first)
		{
		    out << '\n' << heading_ << "Module Index" << body_ << '\n';
		    first = false;
		}

		intro(desc -> id, desc -> name, out);
	    }
	}
	if(!first)
	    out << '\n';

	//
	// Interface index
	//
	first = true;
	for(i = 0 ; i < seq.length() ; i++)
	{
	    if(seq[i].kind == CORBA_dk_Interface)
	    {
		CORBA_InterfaceDescription* desc;
		CORBA_Boolean b = seq[i].value >>= desc;
		assert(b);

		if(first)
		{
		    out << '\n' << heading_ << "Interface Index" << body_
			<< '\n';
		    first = false;
		}

		intro(desc -> id, desc -> name, out);
	    }
	}
	if(!first)
	    out << '\n';
    }

    // ------------------------------------------------------------
    // Pass 2: Description generation
    // ------------------------------------------------------------
     
    int status = 0;

    //
    // Alias description
    //
    first = true;
    for(i = 0 ; i < seq.length() && status == 0 ; i++)
    {
	if(seq[i].kind == CORBA_dk_Alias)
	{
	    CORBA_TypeDescription* desc;
	    CORBA_Boolean b = seq[i].value >>= desc;
	    assert(b);

	    if(first)
	    {
		out << '\n' << heading_ << "Aliases" << body_ << '\n';
		first = false;
	    }

	    CORBA_TypeCode_var origType = desc -> type -> content_type();
	    CORBA_TypeCode_var origOrigType = OBGetOrigType(origType);

	    CORBA_String_var norm = getTypeString(scope, origType,
						  GetTypeNormal,
						  desc -> name);

	    out << '\n' << boldon_ << desc -> name << boldoff_;
	    out.inc();
	    out << '\n' << literal_;

	    out << "typedef " << norm << ';';

	    out << body_;

	    out << '\n';

	    comment(desc -> id, out);

	    out.dec();
	}
    }

    //
    // Constant description
    //
    first = true;
    for(i = 0 ; i < seq.length() && status == 0 ; i++)
    {
	if(seq[i].kind == CORBA_dk_Constant)
	{
	    CORBA_ConstantDescription* desc;
	    CORBA_Boolean b = seq[i].value >>= desc;
	    assert(b);

	    if(first)
	    {
		out << '\n' << heading_ << "Constants" << body_ << '\n';
		first = false;
	    }

	    CORBA_ScopedName_var absolute = getAbsolute(desc -> id);
	    
	    out << '\n' << boldon_ << desc -> name << boldoff_;
	    out.inc();
	    out << '\n' << literal_;

	    CORBA_String_var s = getTypeString(scope, desc -> type,
					       GetTypeNormal, desc -> name);

	    out << "const " << 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 << "'" << s << "'";
		break;
	    }

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

	    default:
		assert(false);
		break;
	    }

	    out << ';';

            out << body_;

	    out << '\n';

	    comment(desc -> id, out);

	    out.dec();
	}
    }

    //
    // Struct description
    //
    first = true;
    for(i = 0 ; i < seq.length() && status == 0 ; i++)
    {
	if(seq[i].kind == CORBA_dk_Struct)
	{
	    CORBA_TypeDescription* desc;
	    CORBA_Boolean b = seq[i].value >>= desc;
	    assert(b);

	    if(first)
	    {
		out << '\n' << heading_ << "Structs" << body_ << '\n';
		first = false;
	    }

	    out << '\n'<< boldon_ << desc -> name << boldoff_;
	    out.inc();
	    out << '\n' << literal_;

	    out << "struct " << desc -> name;

	    out.start();

	    for(j = 0 ; j < desc -> type -> member_count() ; j++)
	    {
		CORBA_TypeCode_var memberType =
		    desc -> type -> member_type(j);
		CORBA_Identifier_var memberName =
		    desc -> type -> member_name(j);

		CORBA_String_var str = getTypeString(scope, memberType,
						     GetTypeNormal,
						     memberName);
		out << '\n' << str << ';';
	    }

	    out.end();
	    out << ';';
		
            out << body_;

	    out << '\n';

	    comment(desc -> id, out);

	    out.dec();
	}
    }

    //
    // Exception description
    //
    first = true;
    for(i = 0 ; i < seq.length() && status == 0 ; i++)
    {
	if(seq[i].kind == CORBA_dk_Exception)
	{
	    CORBA_ExceptionDescription* desc;
	    CORBA_Boolean b = seq[i].value >>= desc;
	    assert(b);

	    if(first)
	    {
		out << '\n' << heading_ << "Exceptions" << body_ << '\n';
		first = false;
	    }

	    out << '\n' << boldon_ << desc -> name << boldoff_;
	    out.inc();
	    out << '\n' << literal_;

	    out << "exception " << desc -> name;

	    out.start();

	    for(j = 0 ; j < desc -> type -> member_count() ; j++)
	    {
		CORBA_TypeCode_var memberType =
		    desc -> type -> member_type(j);
		CORBA_Identifier_var memberName =
		    desc -> type -> member_name(j);

		CORBA_String_var str = getTypeString(scope, memberType,
						     GetTypeNormal,
						     memberName);
		out << '\n' << str << ';';
	    }

	    out.end();
	    out << ';';
		
            out << body_;

	    out << '\n';

	    comment(desc -> id, out);

	    out.dec();
	}
    }

    //
    // Union description
    //
    first = true;
    for(i = 0 ; i < seq.length() && status == 0 ; i++)
    {
	if(seq[i].kind == CORBA_dk_Union)
	{
	    CORBA_TypeDescription* desc;
	    CORBA_Boolean b = seq[i].value >>= desc;
	    assert(b);

	    if(first)
	    {
		out << '\n' << heading_ << "Unions" << body_ << '\n';
		first = false;
	    }

	    CORBA_TypeCode_var discType =
		desc -> type -> discriminator_type();
	    CORBA_String_var disc = getTypeString(scope, discType);

	    IdlUnionMemberInfoSeq_var infoSeq = IdlGetUnionInfo(desc -> type);

	    out << '\n' << boldon_ << desc -> name << boldoff_;
	    out.inc();
	    out << '\n' << literal_;

	    out << "union " << desc -> name;
	    out << " switch(" << disc << ')';
	    out.start();
	    for(j = 0 ; j < infoSeq -> length() ; j++)
	    {
		IdlUnionMemberInfo& info = infoSeq[j];

		printUnionLabels(info, out, discType);

		if(!CORBA_is_nil(info.type))
		{
		    CORBA_String_var norm =
			getTypeString(scope, info.type, GetTypeNormal,
				      info.name);

		    out << ' ' << norm << ';';
		}
	    }

	    out.end();
	    out << ';';

	    out << body_;

	    out << '\n';

	    comment(desc -> id, out);

	    out.dec();
	}
    }

    //
    // Enum description
    //
    first = true;
    for(i = 0 ; i < seq.length() && status == 0 ; i++)
    {
	if(seq[i].kind == CORBA_dk_Enum)
	{
	    CORBA_TypeDescription* desc;
	    CORBA_Boolean b = seq[i].value >>= desc;
	    assert(b);

	    if(first)
	    {
		out << '\n' << heading_ << "Enums" << body_ << '\n';
		first = false;
	    }

	    out << '\n' << boldon_ << desc -> name << boldoff_;
	    out.inc();
	    out << '\n' << literal_;

	    out << "enum " << desc -> name;
	    out.start();

	    for(j = 0 ; j < desc -> type -> member_count() ; j++)
	    {
		CORBA_Identifier_var memberName =
		    desc -> type -> member_name(j);
		out << '\n' << memberName;
		if(j < desc -> type -> member_count() - 1)
		    out << ',';
	    }
	    
	    out.end();
	    out << ';';

	    out << body_;

	    out << '\n';

	    comment(desc -> id, out);

	    out.dec();
	}
    }

    //
    // Attribute Description
    //
    first = true;
    for(i = 0 ; i < seq.length() && status == 0 ; i++)
    {
	if(seq[i].kind == CORBA_dk_Attribute)
	{
	    CORBA_AttributeDescription* desc;
	    CORBA_Boolean b = seq[i].value >>= desc;
	    assert(b);

	    if(first)
	    {
		out << '\n' << heading_ << "Attributes" << body_ << '\n';
		first = false;
	    }

	    out << '\n' << boldon_ << desc -> name << boldoff_;
	    out.inc();
	    out << '\n' << literal_;

	    if(desc -> mode == CORBA_ATTR_READONLY)
		out << "readonly ";

	    CORBA_String_var ret = getTypeString(scope, desc -> type);

	    out << "attribute " << ret << ' ' << desc -> name << ';';

            out << body_;

	    out << '\n';

	    comment(desc -> id, out);

	    out.dec();
	}
    }

    //
    // Operation description
    //
    first = true;
    for(i = 0 ; i < seq.length() && status == 0 ; i++)
    {
	if(seq[i].kind == CORBA_dk_Operation)
	{
	    CORBA_OperationDescription* desc;
	    CORBA_Boolean b = seq[i].value >>= desc;
	    assert(b);
	    
	    if(first)
	    {
		out << '\n' << heading_ << "Operations" << body_ << '\n';
		first = false;
	    }

	    out << '\n' << boldon_ << desc -> name << boldoff_;
	    out.inc();
	    out << '\n' << literal_;

	    if(desc -> mode == CORBA_OP_ONEWAY)
		out << "oneway ";

	    CORBA_String_var ret = getTypeString(scope, desc -> result);
	    
	    out << ret << ' ' << desc -> name << "(";
	    
	    unsigned int pos = 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 s =
		    getTypeString(scope, desc -> parameters[j].type, tt,
				  desc -> parameters[j].name);

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

		    //
		    // Indentation has to be done manually here
		    //
		    for(k = 0 ; k < pos; k++)
			out << ' ';
		}

		out << s;
	    }

	    out << ')';

	    if(desc -> contexts.length() > 0)
	    {
		out.inc();
		out << "\ncontext(";

		for(j = 0 ; j < desc -> contexts.length() ; j++)
		{
		    if(j > 0)
			out << ", ";

		    out << "\"" << desc -> contexts[j] << "\"";
		}

		out << ')';
		out.dec();
	    }

	    if(desc -> exceptions.length())
	    {
		out.inc();
		out << "\nraises(";

		for(j = 0 ; j < desc -> exceptions.length() ; j++)
		{
		    if(j)
			out << ",\n       ";

		    CORBA_String_var str =
			getTypeString(scope, desc -> exceptions[j].type);

		    out << str;
		}
		
		out << ')';

		out.dec();
	    }

	    out << ';';

            out << body_;

	    out << '\n';

	    comment(desc -> id, out);

	    out.dec();
	}
    }

    //
    // Page break for single-file mode
    //
    if(strlen(singleFile_) > 0)
	out << "\\pard \\pagebb";
    else
	out << '\n';
 
    //
    // Interface description
    //
    // (Module descriptions and interface descriptions must be second
    // last for single-file mode)
    //
    for(i = 0 ; i < seq.length() && status == 0 ; i++)
    {
	if(seq[i].kind == CORBA_dk_Interface)
	{
	    CORBA_InterfaceDescription* desc;
	    CORBA_Boolean b = seq[i].value >>= desc;
	    assert(b);

	    //
	    // Get container
	    //
	    CORBA_Container_var cont =
		CORBA_Container::_narrow(seq[i].contained_object);
	    assert(!CORBA_is_nil(cont));

	    CORBA_ScopedName_var absolute = getAbsolute(desc -> id);

	    if(!strlen(singleFile_))
	    {
		//
		// RTF file for the interface
		//
		CORBA_String_var path = fixAbsolute(absolute);
		PrettyPrint out(prog_, path, outDir_, bodyFont_, literalFont_,
				titleFont_, headingFont_);
		if(!out.good())
		    return 1;

		//
		// Generate code
		//
		out << title_ << "Interface " << absolute << body_
		    << "\n\ninterface " << boldon_ << desc -> name << boldoff_;
 
		if(desc -> base_interfaces.length() > 0)
		{
		    out << "\ninherits from ";

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

			if(j > 0)
			    out << ", ";
 
			out << baseAbsolute;
		    }
		}

		out << '\n';

		comment(desc -> id, out);
    
		status = genRTF(cont, out);

		out << '\n';
	    }
	    else
	    {
		//
		// Generate code
		//
		out << title_ << "Interface " << absolute << body_
		    << "\n\ninterface " << boldon_ << desc -> name << boldoff_;
 
		if(desc -> base_interfaces.length() > 0)
		{
		    out << "\ninherits from ";

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

			if(j > 0)
			    out << ", ";
 
			out << baseAbsolute;
		    }
		}

		out << '\n';

		comment(desc -> id, out);
    
		status = genRTF(cont, out);
	    }
 	}
    }

    //
    // Module description
    //
    // (Module descriptions and interface descriptions must be last for
    // single-file mode)
    //
    for(i = 0 ; i < seq.length() && status == 0 ; i++)
    {
	if(seq[i].kind == CORBA_dk_Module)
	{
	    CORBA_ModuleDescription* desc;
	    CORBA_Boolean b = seq[i].value >>= desc;
	    assert(b);

	    //
	    // Get container
	    //
	    CORBA_Container_var cont =
		CORBA_Container::_narrow(seq[i].contained_object);
	    assert(!CORBA_is_nil(cont));

	    CORBA_ScopedName_var absolute = getAbsolute(desc -> id);

	    if(!strlen(singleFile_))
	    {
		//
		// RTF file for the interface
		//
		CORBA_String_var path = fixAbsolute(absolute);
		PrettyPrint out(prog_, path, outDir_, bodyFont_, literalFont_,
				titleFont_, headingFont_);
		if(!out.good())
		    return 1;

		//
		// Generate code
		//
		out << title_ << "Module " << absolute << body_ << '\n';

		comment(desc -> id, out);

		status = genRTF(cont, out);

		out << '\n';
	    }
	    else
	    {
		//
		// Generate code
		//
		out << title_ << "Module " << absolute << body_ << '\n';

		comment(desc -> id, out);

		status = genRTF(cont, out);
	    }
	}
    }

    return status;
}

// ----------------------------------------------------------------------
// IDL code generator constructor and destructor
// ----------------------------------------------------------------------

IdlRTFGenerator::IdlRTFGenerator(const char* prog,
				 CORBA_Repository_ptr rep,
				 const IdlCommentSeq& commentSeq,
				 const char* outDir,
				 const char* singleFile,
				 bool noSort,
				 bool ignoreCase,
				 bool withIndex,
				 const char* bodyFont,
				 const char* literalFont,
				 const char* titleFont,
				 const char* headingFont,
				 unsigned int bodySize,
				 unsigned int literalSize,
				 unsigned int titleSize,
				 unsigned int headingSize)
    : prog_(prog),
      repository_(CORBA_Repository::_duplicate(rep)),
      commentSeq_(commentSeq),
      noSort_(noSort),
      ignoreCase_(ignoreCase),
      withIndex_(withIndex),
      outDir_(outDir),
      singleFile_(singleFile),
      bodyFont_(bodyFont),
      literalFont_(literalFont),
      titleFont_(titleFont),
      headingFont_(headingFont)
{
    keywordSeq_.append(keyException_);
    keywordSeq_.append(keyMember_);
    keywordSeq_.append(keyParam_);
    keywordSeq_.append(keyReturn_);
    keywordSeq_.append(keySee_);
    keywordSeq_.append(keySince_);
    keywordSeq_.append(keyAuthor_);
    keywordSeq_.append(keyVersion_);

    //
    // Define fonts and sizes
    //
    body_ = CORBA_string_dup("\\f0\\fs");
    body_ += bodySize;
    body_ += ' ';
    literal_ = CORBA_string_dup("\\f1\\fs");
    literal_ += literalSize;
    literal_ += ' ';
    title_ = CORBA_string_dup("\\f2\\fs");
    title_ += titleSize;
    title_ += ' ';
    heading_ = CORBA_string_dup("\\f3\\fs");
    heading_ += headingSize;
    heading_ += ' ';
}

// ----------------------------------------------------------------------
// Generate RTF code
// ----------------------------------------------------------------------

int
IdlRTFGenerator::gen()
{
    if(!strlen(singleFile_))
    {
	PrettyPrint out(prog_, top_, outDir_, bodyFont_, literalFont_,
			titleFont_, headingFont_);

	out << title_ << "Top-Level Module" << body_ << '\n';
	return genRTF(repository_, out);
    }
    else
    {
	PrettyPrint out(prog_, singleFile_, outDir_, bodyFont_, literalFont_,
			titleFont_, headingFont_);

	out << title_ << "Top-Level Module" << body_ << '\n';
	return genRTF(repository_, out);
    }
}
