use strict;
use warnings;
package Clownfish::Binding::Core::File;
use Clownfish::Util qw( a_isa_b verify_args );
use Clownfish::Binding::Core::Class;
use File::Spec::Functions qw( catfile splitpath );
use File::Path qw( mkpath );
use Scalar::Util qw( blessed );
use Fcntl;
use Carp;
my %write_h_PARAMS = (
file => undef,
dest => undef,
header => undef,
footer => undef,
);
sub write_h {
my ( undef, %args ) = @_;
verify_args( \%write_h_PARAMS, %args ) or confess $@;
my $file = $args{file};
confess("Not a Clownfish::File")
unless a_isa_b( $file, "Clownfish::File" );
my $h_path = $file->h_path( $args{dest} );
# Unlink then open file.
my ( undef, $out_dir, undef ) = splitpath($h_path);
mkpath $out_dir unless -d $out_dir;
confess("Can't make dir '$out_dir'") unless -d $out_dir;
unlink $h_path;
sysopen( my $fh, $h_path, O_CREAT | O_EXCL | O_WRONLY )
or confess("Can't open '$h_path' for writing");
# Create the include-guard strings.
my $include_guard_start = $file->guard_start;
my $include_guard_close = $file->guard_close;
# Aggregate block content.
my $content = "";
for my $block ( $file->blocks ) {
if ( a_isa_b( $block, 'Clownfish::Parcel' ) ) { }
elsif ( a_isa_b( $block, 'Clownfish::Class' ) ) {
my $class_binding
= Clownfish::Binding::Core::Class->new( client => $block, );
$content .= $class_binding->to_c_header . "\n";
}
elsif ( a_isa_b( $block, 'Clownfish::CBlock' ) ) {
$content .= $block->get_contents . "\n";
}
else {
confess("Invalid block: $block");
}
}
print $fh <<END_STUFF;
$args{header}
$include_guard_start
#ifdef __cplusplus
extern "C" {
#endif
$content
#ifdef __cplusplus
}
#endif
$include_guard_close
$args{footer}
END_STUFF
}
my %write_c_PARAMS = (
file => undef,
dest => undef,
header => undef,
footer => undef,
);
sub write_c {
my ( undef, %args ) = @_;
verify_args( \%write_h_PARAMS, %args ) or confess $@;
my $file = $args{file};
confess("Not a Clownfish::File")
unless a_isa_b( $file, "Clownfish::File" );
my $c_path = $file->c_path( $args{dest} );
# Unlink then open file.
my ( undef, $out_dir, undef ) = splitpath($c_path);
mkpath $out_dir unless -d $out_dir;
confess("Can't make dir '$out_dir'") unless -d $out_dir;
unlink $c_path;
sysopen( my $fh, $c_path, O_CREAT | O_EXCL | O_WRONLY )
or confess("Can't open '$c_path' for writing");
# Aggregate content.
my $content = "";
my $c_file_syms = "";
for my $block ( $file->blocks ) {
if ( blessed($block) ) {
if ( $block->isa('Clownfish::Class') ) {
my $bound
= Clownfish::Binding::Core::Class->new( client => $block,
);
$content .= $bound->to_c . "\n";
my $c_file_sym = "C_" . uc( $block->full_struct_sym );
$c_file_syms .= "#define $c_file_sym\n";
}
}
}
print $fh <<END_STUFF;
$args{header}
$c_file_syms
#define C_KINO_VTABLE
#define C_KINO_ZOMBIECHARBUF
#include "boil.h"
#include "KinoSearch/Object/VTable.h"
#include "KinoSearch/Object/CharBuf.h"
#include "KinoSearch/Object/Err.h"
#include "KinoSearch/Object/Hash.h"
#include "KinoSearch/Object/Host.h"
#include "KinoSearch/Object/VArray.h"
$content
$args{footer}
END_STUFF
}
1;
__END__
__POD__
=head1 NAME
Clownfish::Binding::Core::File - Generate core C code for a Clownfish file.
=head1 DESCRIPTION
This module is the companion to Clownfish::File, generating the C code
needed to implement the file's specification.
There is a one-to-one mapping between Clownfish header files and autogenerated
.h and .c files. If Foo.cfh includes both Foo and Foo::FooJr, then it is
necessary to pound-include "Foo.h" in order to get FooJr's interface -- not
"Foo/FooJr.h", which won't exist.
=head1 CLASS METHODS
=head2 write_h
Clownfish::Binding::Core::File->write_c(
file => $file, # required
dest => '/path/to/autogen_dir', # required
header => "/* Autogenerated file. */\n", # required
footer => $copyfoot, # required
);
Generate a C header file containing all class declarations and literal C
blocks.
=over
=item * B<file> - A L<Clownfish::File>.
=item * B<dest> - The directory under which autogenerated files are being
written.
=item * B<header> - Text which will be prepended to each generated C file --
typically, an "autogenerated file" warning.
=item * B<footer> - Text to be appended to the end of each generated C file --
typically copyright information.
=back
=head2 write_h
Clownfish::Binding::Core::File->write_c(
file => $file, # required
dest => '/path/to/autogen_dir', # required
header => "/* Autogenerated file. */\n", # required
footer => $copyfoot, # required
);
Generate a C file containing code needed by the class implementations.
=head1 COPYRIGHT AND LICENSE
Copyright 2008-2011 Marvin Humphrey
This program is free software; you can redistribute it and/or modify it under
the same terms as Perl itself.
=cut