
#
#           Interface Definition Language (OMG IDL CORBA v3.0)
#
#           C Language Mapping Specification, New Edition June 1999
#

package CORBA::C::IncludeVisitor;

use strict;
use warnings;

our $VERSION = '2.62';

use File::Basename;
use POSIX qw(ctime);

# needs $node->{repos_id} (repositoryIdVisitor), $node->{c_name} (CnameVisitor)
# $node->{c_arg} (CtypeVisitor) and $node->{c_literal} (CliteralVisitor)

sub new {
    my $proto = shift;
    my $class = ref($proto) || $proto;
    my $self = {};
    bless $self, $class;
    my ($parser, $incpath) = @_;
    $self->{incpath} = $incpath || q{};
    $self->{prefix} = q{};              # provision for incskel
    $self->{srcname} = $parser->YYData->{srcname};
    $self->{srcname_size} = $parser->YYData->{srcname_size};
    $self->{srcname_mtime} = $parser->YYData->{srcname_mtime};
    $self->{symbtab} = $parser->YYData->{symbtab};
    $self->{inc} = {};
    my $filename = basename($self->{srcname}, '.idl') . '.h';
    $self->open_stream($filename);
    $self->{done_hash} = {};
    $self->{num_key} = 'num_inc_c';
    return $self;
}

sub open_stream {
    my $self = shift;
    my ($filename) = @_;
    open $self->{out}, '>', $filename
            or die "can't open $filename ($!).\n";
    $self->{filename} = $filename;
}

sub _insert_inc {
    my $self = shift;
    my ($filename) = @_;
    my $FH = $self->{out};
    unless (exists $self->{inc}->{$filename}) {
        $self->{inc}->{$filename} = 1;
        $filename = basename($filename, '.idl') . '.h';
        print $FH "#include \"",$self->{prefix},$filename,"\"\n";
    }
}

sub _no_mapping {
    my $self = shift;
    my ($node) = @_;
    my $FH = $self->{out};
    if ($self->{srcname} eq $node->{filename}) {
        my $class = ref $node;
        $class = substr $class, rindex($class, ':') + 1;
        if ($class =~ /^Forward/) {
            $node = $self->{symbtab}->Lookup($node->{full});
        }
        print $FH "\n";
        print $FH "/* no mapping for ",$node->{c_name}," */\n";
        print $FH "\n";
    }
    else {
        $self->_insert_inc($node->{filename});
    }
}

sub _get_defn {
    my $self = shift;
    my ($defn) = @_;
    if (ref $defn) {
        return $defn;
    }
    else {
        return $self->{symbtab}->Lookup($defn);
    }
}

#
#   3.5     OMG IDL Specification
#

sub visitSpecification {
    my $self = shift;
    my ($node) = @_;
    my $FH = $self->{out};
    print $FH "/* ex: set ro: */\n";
    print $FH "/* This file was generated (by ",basename($0),"). DO NOT modify it */\n";
    print $FH "/* From file : ",$self->{srcname},", ",$self->{srcname_size}," octets, ",POSIX::ctime($self->{srcname_mtime});
    print $FH " */\n";
    print $FH "\n";
    print $FH "#include <",$self->{incpath},"corba.h>\n";
#   print $FH "#include \"corba.h\"\n";
    print $FH "\n";
    if (exists $node->{list_import}) {
        foreach (@{$node->{list_import}}) {
            my $basename = $_->{value};
            $basename =~ s/^:://;
            $basename =~ s/::/_/g;
            print $FH "#include \"",$basename,".h\"\n";
        }
        print $FH "\n";
    }
    foreach (@{$node->{list_decl}}) {
        $self->_get_defn($_)->visit($self);
    }
    print $FH "\n";
    print $FH "/* end of file : ",$self->{filename}," */\n";
    print $FH "\n";
    print $FH "/*\n";
    print $FH " * Local variables:\n";
    print $FH " *   buffer-read-only: t\n";
    print $FH " * End:\n";
    print $FH " */\n";    
    close $FH;
}

#
#   3.7     Module Declaration
#

sub visitModules {
    my $self = shift;
    my ($node) = @_;
    unless (exists $node->{$self->{num_key}}) {
        $node->{$self->{num_key}} = 0;
    }
    my $module = ${$node->{list_decl}}[$node->{$self->{num_key}}];
    $module->visit($self);
    $node->{$self->{num_key}} ++;
}

sub visitModule {
    my $self = shift;
    my ($node) = @_;
    my $FH = $self->{out};
    if ($self->{srcname} eq $node->{filename}) {
        my $filename = basename($self->{srcname}, '.idl') . '.h';
        $filename =~ s/\./_/g;
        my $defn = $self->{symbtab}->Lookup($node->{full});
        print $FH "/*\n";
        print $FH " * begin of module ",$defn->{c_name},"\n";
        print $FH " */\n";
        print $FH "#ifndef _",$self->{prefix},$defn->{c_name},"_",$filename,"_defined\n";
        print $FH "#define _",$self->{prefix},$defn->{c_name},"_",$filename,"_defined\n";
        print $FH "\n";
        foreach (@{$node->{list_decl}}) {
            $self->_get_defn($_)->visit($self);
        }
        print $FH "#endif\n";
        print $FH "/*\n";
        print $FH " * end of module ",$defn->{c_name},"\n";
        print $FH " */\n";
    }
    else {
        $self->_insert_inc($node->{filename});
    }
}

#
#   3.8     Interface Declaration
#
#   See 1.3     Mapping for Interfaces
#

sub visitRegularInterface {
    my $self = shift;
    my ($node) = @_;
    my $FH = $self->{out};
    $self->{itf} = $node->{c_name};
    if ($self->{srcname} eq $node->{filename}) {
        print $FH "/*\n";
        print $FH " * begin of interface ",$node->{c_name},"\n";
        print $FH " */\n";
        print $FH "#ifndef _",$self->{prefix},$node->{c_name},"_defined\n";
        print $FH "#define _",$self->{prefix},$node->{c_name},"_defined\n";
        print $FH "\n";
        if (exists $self->{reposit}) {
            print $FH "#define id_",$node->{c_name}," \"",$node->{repos_id},"\"\n";
        }
        print $FH "typedef CORBA_Object ",$node->{c_name},";\n";
        print $FH "\n";
        foreach (@{$node->{list_decl}}) {
            my $defn = $self->_get_defn($_);
            if (       $defn->isa('Operation')
                    or $defn->isa('Attributes') ) {
                next;
            }
            $defn->visit($self);
        }
        print $FH "#endif\n";
        print $FH "\n";
        if (keys %{$node->{hash_attribute_operation}}) {
            print $FH "#ifndef _proto_",$self->{prefix},$node->{c_name},"_defined\n";
            print $FH "#define _proto_",$self->{prefix},$node->{c_name},"_defined\n";
            print $FH "\n";
            $self->{itf} = $node->{c_name};
            foreach (values %{$node->{hash_attribute_operation}}) {
                $self->_get_defn($_)->visit($self);
            }
            delete $self->{itf};
            print $FH "#endif\n";
        }
        print $FH "/*\n";
        print $FH " * end of interface ",$node->{c_name},"\n";
        print $FH " */\n";
    }
    else {
        $self->_insert_inc($node->{filename});
    }
}

sub visitAbstractInterface {
    # C mapping is aligned with CORBA 2.1
    my $self = shift;
    my ($node) = @_;
    my $FH = $self->{out};
    $self->{itf} = $node->{c_name};
    if ($self->{srcname} eq $node->{filename}) {
        print $FH "/*\n";
        print $FH " * begin of abstract interface ",$node->{c_name},"\n";
        print $FH " */\n";
        print $FH "#ifndef _",$self->{prefix},$node->{c_name},"_defined\n";
        print $FH "#define _",$self->{prefix},$node->{c_name},"_defined\n";
        print $FH "\n";
        print $FH "typedef CORBA_Object ",$node->{c_name},";\n";
        print $FH "\n";
        foreach (@{$node->{list_decl}}) {
            my $defn = $self->_get_defn($_);
            if (       $defn->isa('Operation')
                    or $defn->isa('Attributes') ) {
                next;
            }
            $defn->visit($self);
        }
        print $FH "#endif\n";
        print $FH "\n";
        print $FH "/*\n";
        print $FH " * end of abstract interface ",$node->{c_name},"\n";
        print $FH " */\n";
    }
    else {
        $self->_insert_inc($node->{filename});
    }
}

sub visitForwardRegularInterface {
    my $self = shift;
    my ($node) = @_;
    my $FH = $self->{out};
    if ($self->{srcname} eq $node->{filename}) {
        my $defn = $self->{symbtab}->Lookup($node->{full});
        print $FH "\n";
        print $FH "typedef ",$defn->{c_name},";\n";
        print $FH "\n";
    }
    else {
        $self->_insert_inc($node->{filename});
    }
}

sub visitForwardAbstractInterface {
    # C mapping is aligned with CORBA 2.1
    my $self = shift;
    my ($node) = @_;
    my $FH = $self->{out};
    if ($self->{srcname} eq $node->{filename}) {
        my $defn = $self->{symbtab}->Lookup($node->{full});
        print $FH "\n";
        print $FH "typedef ",$defn->{c_name},";\n";
        print $FH "\n";
    }
    else {
        $self->_insert_inc($node->{filename});
    }
}

sub visitBaseInterface {
    # C mapping is aligned with CORBA 2.1
    shift->_no_mapping(@_);
}

sub visitForwardBaseInterface {
    # C mapping is aligned with CORBA 2.1
    shift->_no_mapping(@_);
}

#
#   3.10    Constant Declaration
#
#   See 1.6     Mapping for Constants
#

sub visitConstant {
    my $self = shift;
    my ($node) = @_;
    my $FH = $self->{out};
    if ($self->{srcname} eq $node->{filename}) {
        print $FH "#define ",$node->{c_name},"\t",$node->{value}->{c_literal},"\n";
    }
    else {
        $self->_insert_inc($node->{filename});
    }
}

#
#   3.11    Type Declaration
#

sub visitTypeDeclarators {
    my $self = shift;
    my ($node) = @_;
    foreach (@{$node->{list_decl}}) {
        $self->_get_defn($_)->visit($self);
    }
}

sub visitTypeDeclarator {
    my $self = shift;
    my ($node) = @_;
    my $type = $self->_get_defn($node->{type});
    if (       $type->isa('StructType')
            or $type->isa('UnionType')
            or $type->isa('EnumType')
            or $type->isa('SequenceType')
            or $type->isa('StringType')
            or $type->isa('WideStringType')
            or $type->isa('FixedPtType') ) {
        $type->visit($self);
    }
    if ($self->{srcname} eq $node->{filename}) {
        my $FH = $self->{out};
        if (exists $self->{reposit}) {
            print $FH "#define id_",$node->{c_name}," \"",$node->{repos_id},"\"\n";
            print $FH "#define uid_",$node->{c_name}," 0x",$node->{serial_uid},"ULL\n"
                    if (exists $node->{serial_uid});
        }
        if (exists $node->{array_size}) {
            #
            #   See 1.15    Mapping for Array
            #
            warn __PACKAGE__,"::visitTypeDecalarator $node->{idf} : empty array_size.\n"
                    unless (@{$node->{array_size}});
            print $FH "typedef ",
                    $type->{c_name},
                    " ",$node->{c_name};
            foreach (@{$node->{array_size}}) {
                print $FH "[",$_->{c_literal},"]";
            }
            print $FH ";\n";
            my @list = @{$node->{array_size}};
            shift @list;
            print $FH "typedef ",
                    $type->{c_name},
                    " ",$node->{c_name},"_slice";
            foreach (@list) {
                print $FH "[",$_->{c_literal},"]";
            }
            print $FH ";\n";
            if (defined $type->{length}) {
                if (exists $self->{use_define}) {
                    print $FH "#define ",$node->{c_name},"__alloc(nb)\t(",$node->{c_name},"_slice *)CORBA_alloc((nb) * sizeof(",$node->{c_name},"_slice))\n";
                }
                else {
                    print $FH "extern ",$node->{c_name},"_slice * ",$node->{c_name},"__alloc(CORBA_unsigned_long nb);\n";
                }
            }
        }
        else {
            print $FH "typedef ",
                    $type->{c_name},
                    " ",$node->{c_name},";\n";
        }
    }
}

sub visitNativeType {
    # empty
}

#
#   3.11.2  Constructed Types
#
#   3.11.2.1    Structures
#
#   See 1.9     Mapping for Structure Types
#

sub visitStructType {
    my $self = shift;
    my ($node) = @_;
    return if (exists $self->{done_hash}->{$node->{c_name}});
    $self->{done_hash}->{$node->{c_name}} = 1;
    foreach (@{$node->{list_expr}}) {
        my $type = $self->_get_defn($_->{type});
        if (       $type->isa('StructType')
                or $type->isa('UnionType')
                or $type->isa('SequenceType')
                or $type->isa('StringType')
                or $type->isa('WideStringType')
                or $type->isa('FixedPtType') ) {
            $type->visit($self);
        }
    }
    my $FH = $self->{out};
    if ($self->{srcname} eq $node->{filename}) {
        if (exists $self->{reposit}) {
            print $FH "#define id_",$node->{c_name}," \"",$node->{repos_id},"\"\n";
            print $FH "#define uid_",$node->{c_name}," 0x",$node->{serial_uid},"ULL\n"
                    if (exists $node->{serial_uid});
        }
        print $FH "typedef struct {\n";
        foreach (@{$node->{list_expr}}) {
            $_->visit($self);               # members
        }
        print $FH "} ",$node->{c_name},";\n";
        if (defined $node->{length}) {
            if (exists $self->{use_define}) {
                print $FH "#define ",$node->{c_name},"__alloc(nb)\t(",$node->{c_name}," *)CORBA_alloc((nb) * sizeof(",$node->{c_name},"))\n"
            }
            else {
                print $FH "extern ",$node->{c_name}," * ",$node->{c_name},"__alloc(CORBA_unsigned_long nb);\n";
            }
        }
    }
    else {
        $self->_insert_inc($node->{filename});
    }
}

sub visitMembers {
    my $self = shift;
    my ($node) = @_;
    my $FH = $self->{out};
    my $type = $self->_get_defn($node->{type});
    print $FH "\t",$type->{c_name};
    my $first = 1;
    foreach (@{$node->{list_member}}) {
        if ($first) {
            $first = 0;
        }
        else {
            print $FH ",";
        }
        $self->_get_defn($_)->visit($self);     # member
    }
    print $FH ";\n";
}

sub visitMember {
    my $self = shift;
    my ($node) = @_;
    my $FH = $self->{out};
    print $FH " ",$node->{c_name};
    if (exists $node->{array_size}) {
        foreach (@{$node->{array_size}}) {
            print $FH "[",$_->{c_literal},"]";
        }
    }
}

#   3.11.2.2    Discriminated Unions
#
#   See 1.10    Mapping for Union Types
#

sub visitUnionType {
    my $self = shift;
    my ($node) = @_;
    return if (exists $self->{done_hash}->{$node->{c_name}});
    $self->{done_hash}->{$node->{c_name}} = 1;
    foreach (@{$node->{list_expr}}) {
        my $type = $self->_get_defn($_->{element}->{type});
        if (       $type->isa('StructType')
                or $type->isa('UnionType')
                or $type->isa('SequenceType')
                or $type->isa('StringType')
                or $type->isa('WideStringType')
                or $type->isa('FixedPtType') ) {
            $type->visit($self);
        }
    }
    my $type = $self->_get_defn($node->{type});
    if ($type->isa('EnumType')) {
        $type->visit($self);
    }
    my $FH = $self->{out};
    if ($self->{srcname} eq $node->{filename}) {
        if (exists $self->{reposit}) {
            print $FH "#define id_",$node->{c_name}," \"",$node->{repos_id},"\"\n";
            print $FH "#define uid_",$node->{c_name}," 0x",$node->{serial_uid},"ULL\n"
                    if (exists $node->{serial_uid});
        }
        print $FH "typedef struct {\n";
        print $FH "\t",$type->{c_name}," _d; /* discriminator */\n";
        print $FH "\tunion {\n";
        foreach (@{$node->{list_expr}}) {
            $_->visit($self);               # case
        }
        print $FH "\t} _u;\n";
        print $FH "} ",$node->{c_name},";\n";
        if (defined $type->{length}) {
            if (exists $self->{use_define}) {
                print $FH "#define ",$node->{c_name},"__alloc(nb)\t(",$node->{c_name}," *)CORBA_alloc((nb) * sizeof(",$node->{c_name},"))\n"
            }
            else {
                print $FH "extern ",$node->{c_name}," * ",$node->{c_name},"__alloc(CORBA_unsigned_long nb);\n";
            }
        }
    }
    else {
        $self->_insert_inc($node->{filename});
    }
}

sub visitCase {
    my $self = shift;
    my ($node) = @_;
    $node->{element}->visit($self);
}

sub visitElement {
    my $self = shift;
    my ($node) = @_;
    my $FH = $self->{out};
    my $type = $self->_get_defn($node->{type});
    print $FH "\t\t",$type->{c_name};
        $self->_get_defn($node->{value})->visit($self);     # member
        print $FH ";\n";
}

#   3.11.2.3    Constructed Recursive Types and Forward Declarations
#

sub visitForwardStructType {
    my $self = shift;
    my ($node) = @_;
    my $FH = $self->{out};
    if ($self->{srcname} eq $node->{filename}) {
        my $defn = $self->{symbtab}->Lookup($node->{full});
        print $FH "typedef ",$defn->{c_name},";\n";
    }
    else {
        $self->_insert_inc($node->{filename});
    }
}

sub visitForwardUnionType {
    my $self = shift;
    my ($node) = @_;
    my $FH = $self->{out};
    if ($self->{srcname} eq $node->{filename}) {
        my $defn = $self->{symbtab}->Lookup($node->{full});
        print $FH "typedef ",$defn->{c_name},";\n";
    }
    else {
        $self->_insert_inc($node->{filename});
    }
}

#   3.11.2.4    Enumerations
#

sub visitEnumType {
    my $self = shift;
    my ($node) = @_;
    return if (exists $self->{done_hash}->{$node->{c_name}});
    $self->{done_hash}->{$node->{c_name}} = 1;
    my $FH = $self->{out};
    if ($self->{srcname} eq $node->{filename}) {
        print $FH "/* enum ",$node->{c_name}," */\n";
        print $FH "#define ",$node->{c_name}," CORBA_unsigned_long\n";
        if (exists $self->{reposit}) {
            print $FH "#define id_",$node->{c_name}," \"",$node->{repos_id},"\"\n";
            print $FH "#define uid_",$node->{c_name}," 0x",$node->{serial_uid},"ULL\n"
                    if (exists $node->{serial_uid});
        }
        foreach (@{$node->{list_expr}}) {
            $_->visit($self);               # enum
        }
        print $FH "\n";
    }
    else {
        $self->_insert_inc($node->{filename});
    }
}

sub visitEnum {
    my $self = shift;
    my ($node) = @_;
    my $FH = $self->{out};
    print $FH "#define ",$node->{c_name},"\t",$node->{c_literal},"\n";
}

#
#   3.11.3  Template Types
#
#   See 1.11    Mapping for Sequence Types
#

sub visitSequenceType {
    my $self = shift;
    my ($node) = @_;
    return if (exists $self->{done_hash}->{$node->{c_name}});
    $self->{done_hash}->{$node->{c_name}} = 1;
    my $FH = $self->{out};
    if ($self->{srcname} eq $node->{filename}) {
        my $type = $self->_get_defn($node->{type});
        if (       $type->isa('SequenceType')
                or $type->isa('StringType')
                or $type->isa('WideStringType')
                or $type->isa('FixedPtType') ) {
            $type->visit($self);
        }
        print $FH "#ifndef _",$node->{c_name},"_defined\n";
        print $FH "#define _",$node->{c_name},"_defined\n";
        print $FH "typedef struct {\n";
        print $FH "\tCORBA_unsigned_long _maximum;\n";
        print $FH "\tCORBA_unsigned_long _length;\n";
        print $FH "\t",$type->{c_name}," * _buffer;\n";
        print $FH "} ",$node->{c_name},";\n";
        if (exists $self->{use_define}) {
            print $FH "#define ",$node->{c_name},"__alloc(nb)\t(",$node->{c_name}," *)CORBA_alloc((nb) * sizeof(",$node->{c_name},"))\n";
            print $FH "#define ",$node->{c_name},"__allocbuf(len)\t(",$type->{c_name}," *)CORBA_alloc((len) * sizeof(",$type->{c_name},"))\n";
        }
        else {
            print $FH "extern ",$node->{c_name}," * ",$node->{c_name},"__alloc(CORBA_unsigned_long nb);\n";
            print $FH "extern ",$type->{c_name}," * ",$node->{c_name},"__allocbuf(CORBA_unsigned_long len);\n";
        }
        print $FH "#endif\n";
    }
}

#
#   See 1.12    Mapping for Strings
#

sub visitStringType {
    my $self = shift;
    my ($node) = @_;
    return if (exists $self->{done_hash}->{$node->{c_name}});
    $self->{done_hash}->{$node->{c_name}} = 1;
    my $FH = $self->{out};
    print $FH "#ifndef _",$node->{c_name},"_defined\n";
    print $FH "#define _",$node->{c_name},"_defined\n";
    print $FH "typedef CORBA_char * ",$node->{c_name},";\n";
    print $FH "#endif\n";
}

#
#   See 1.13    Mapping for Wide Strings
#

sub visitWideStringType {
    my $self = shift;
    my ($node) = @_;
    return if (exists $self->{done_hash}->{$node->{c_name}});
    $self->{done_hash}->{$node->{c_name}} = 1;
    my $FH = $self->{out};
    print $FH "#ifndef _",$node->{c_name},"_defined\n";
    print $FH "#define _",$node->{c_name},"_defined\n";
    print $FH "typedef CORBA_wchar * ",$node->{c_name},";\n";
    print $FH "#endif\n";
}

#
#   See 1.14    Mapping for Fixed
#

sub visitFixedPtType {
    my $self = shift;
    my ($node) = @_;
    my $FH = $self->{out};
    if ($self->{srcname} eq $node->{filename}) {
        print $FH "#ifndef _",$node->{c_name},"_defined\n";
        print $FH "#define _",$node->{c_name},"_defined\n";
        print $FH "typedef struct {\n";
        print $FH "\tCORBA_unsigned_short _digits;\n";
        print $FH "\tCORBA_short _scale;\n";
        print $FH "\tCORBA_char _value [(",
                $node->{d}->{value}, "+",
                $node->{s}->{value}, ")/2];\n";
        print $FH "} ",$node->{c_name},";\n";
        # alloc : TODO
        print $FH "#endif\n";
    }
}

sub visitFixedPtConstType {
    # empty
}

#
#   3.12    Exception Declaration
#
#   See 1.16    Mapping for Exception Types
#

sub visitException {
    my $self = shift;
    my ($node) = @_;
    if (exists $node->{list_expr}) {
        warn __PACKAGE__,"::visitException $node->{idf} : empty list_expr.\n"
                unless (@{$node->{list_expr}});
        foreach (@{$node->{list_expr}}) {
            my $type = $self->_get_defn($_->{type});
            if (       $type->isa('StructType')
                    or $type->isa('UnionType')
                    or $type->isa('SequenceType')
                    or $type->isa('StringType')
                    or $type->isa('WideStringType')
                    or $type->isa('FixedPtType') ) {
                $type->visit($self);
            }
        }
    }
    my $FH = $self->{out};
    if ($self->{srcname} eq $node->{filename}) {
        print $FH "/* exception ",$node->{c_name}," */\n";
        print $FH "typedef struct ",$node->{c_name}," {\n";
        if (exists $node->{list_expr}) {
            foreach (@{$node->{list_expr}}) {
                $_->visit($self);               # members
            }
        }
        else {
            print $FH "\tCORBA_long _dummy;\n";
        }
        print $FH "} ",$node->{c_name},";\n";
        print $FH "#define ex_",$node->{c_name}," \"",$node->{repos_id},"\"\n";
        if (exists $self->{reposit}) {
            print $FH "#define uid_",$node->{c_name}," 0x",$node->{serial_uid},"ULL\n"
                    if (exists $node->{serial_uid});
        }
        if (exists $self->{use_define}) {
            print $FH "#define ",$node->{c_name},"__alloc(nb)\t(",$node->{c_name}," *)CORBA_alloc((nb) * sizeof(",$node->{c_name},"))\n";
        }
        else {
            print $FH "extern ",$node->{c_name}," * ",$node->{c_name},"__alloc(CORBA_unsigned_long nb);\n";
        }
        print $FH "\n";
    }
    else {
        $self->_insert_inc($node->{filename});
    }
}

#
#   3.13    Operation Declaration
#

sub visitOperation {
    my $self = shift;
    my ($node) = @_;
    foreach (@{$node->{list_param}}) {
        my $type = $self->_get_defn($_->{type});
        if (       $type->isa('StringType')
                or $type->isa('WideStringType') ) {
            $type->visit($self);
        }
    }
    my $FH = $self->{out};
    print $FH "extern ",$node->{c_arg}," ",$self->{prefix},$self->{itf},"_",$node->{c_name},"(\n";
    print $FH "\t",$self->{itf}," _o,\n";
    foreach (@{$node->{list_param}}) {
        $_->visit($self);               # parameter
    }
    print $FH "\tCORBA_Context _ctx,\n"
            if (exists $node->{list_context});
    print $FH "\tCORBA_Environment * _ev\n";
    print $FH ");\n";
}

sub visitParameter {
    my $self = shift;
    my ($node) = @_;
    my $FH = $self->{out};
    my $type = $self->_get_defn($node->{type});
    print $FH "\t",$node->{c_arg},", /* ",$node->{attr};
        print $FH " (variable length) */\n" if (defined $type->{length});
        print $FH " (fixed length) */\n" unless (defined $type->{length});
}

#
#   3.14    Attribute Declaration
#

sub visitAttribute {
    my $self = shift;
    my ($node) = @_;
    $node->{_get}->visit($self);
    $node->{_set}->visit($self) if (exists $node->{_set});
}

#
#   3.15    Repository Identity Related Declarations
#

sub visitTypeId {
    # empty
}

sub visitTypePrefix {
    # empty
}

#
#   XPIDL
#

sub visitCodeFragment {
    # empty
}

##############################################################################

package CORBA::C::IncDefVisitor;

use strict;
use warnings;

use base qw(CORBA::C::IncludeVisitor);

use File::Basename;

sub new {
    my $proto = shift;
    my $class = ref($proto) || $proto;
    my $self = {};
    bless $self, $class;
    my ($parser, $incpath) = @_;
    $self->{incpath} = $incpath || q{};
    $self->{prefix} = q{};
    $self->{srcname} = $parser->YYData->{srcname};
    $self->{srcname_size} = $parser->YYData->{srcname_size};
    $self->{srcname_mtime} = $parser->YYData->{srcname_mtime};
    $self->{symbtab} = $parser->YYData->{symbtab};
    $self->{inc} = {};
    $self->{use_define} = 1;
    $self->{reposit} = 1;
    my $filename = basename($self->{srcname}, '.idl') . '.h';
    $self->open_stream($filename);
    $self->{done_hash} = {};
    $self->{num_key} = 'num_inc_c';
    return $self;
}

1;

