# # this is all hacky etc. it works so it's gonna stay for now. it is not and # should not be installed. # # $Header: /cvs/cairo/cairo-perl/MakeHelper.pm,v 1.11 2006/12/30 19:16:31 tsch Exp $ # package MakeHelper; use strict; use warnings; use IO::File; use File::Spec; our $autogen_dir = '.'; # --------------------------------------------------------------------------- # # copied/borrowed from Gtk2-Perl's CodeGen sub write_boot { my %opts = ( ignore => '^[^:]+$', # ignore package with no colons in it filename => File::Spec->catdir ($autogen_dir, 'cairo-perl-boot.xsh'), 'glob' => File::Spec->catfile ('xs', '*.xs'), @_, ); my $ignore = $opts{ignore}; my $file = IO::File->new (">$opts{filename}") or die "Cannot write $opts{filename}: $!"; print $file "\n\n/* This file is automatically generated, any changes made here will be lost! */\n\n"; my %boot=(); my @xs_files = 'ARRAY' eq ref $opts{xs_files} ? @{ $opts{xs_files} } : glob $opts{'glob'}; foreach my $xsfile (@xs_files) { my $in = IO::File->new ($xsfile) or die "can't open $xsfile: $!\n"; while (<$in>) { next unless m/^MODULE\s*=\s*(\S+)/; #warn "found $1 in $&\n"; my $package = $1; next if $package =~ m/$ignore/; $package =~ s/:/_/g; my $sym = "boot_$package"; print $file "CAIRO_PERL_CALL_BOOT ($sym);\n" unless $boot{$sym}; $boot{$sym}++; } close $in; } close $file; } # --------------------------------------------------------------------------- # sub do_typemaps { my %objects = %{shift ()}; my %structs = %{shift ()}; my %enums = %{shift ()}; my %backend_guards = %{shift ()}; my %enum_guards = %{shift ()}; my $cairo_perl = File::Spec->catfile ($autogen_dir, 'cairo-perl-auto.typemap'); open TYPEMAP, '>', $cairo_perl or die "unable to open ($cairo_perl) for output"; print TYPEMAP <catfile ($autogen_dir, 'cairo-perl-auto.h'); open HEADER, '>', $header or die "unable to open ($header) for output"; print HEADER < EOS sub mangle { my $mangled = shift; $mangled =~ s/_t$//; $mangled =~ s/([^_]+)/ucfirst $1/ge; $mangled =~ s/_//g; return $mangled; } sub reference { my $ref = shift; $ref =~ s/_t$//; $ref .= '_reference'; return $ref; } sub name { $_[0] =~ /cairo_(\w+)_t/; return $1; } # ------------------------------------------------------------------- # print HEADER "\n/* objects */\n\n"; foreach (keys %objects) { /^(.+) \*/; my $type = $1; my $mangled = mangle ($type); my $ref = reference ($type); if (exists $backend_guards{$type}) { print HEADER "#ifdef $backend_guards{$type}\n"; } print HEADER <<"EOS"; typedef $type ${type}_noinc; typedef $type ${type}_ornull; #define Sv$mangled(sv) (($type *) cairo_object_from_sv (sv, "$objects{$_}")) #define Sv${mangled}_ornull(sv) (((sv) && SvOK (sv)) ? Sv$mangled(sv) : NULL) #define newSV$mangled(object) (cairo_object_to_sv (($type *) $ref (object), "$objects{$_}")) #define newSV${mangled}_noinc(object) (cairo_object_to_sv (($type *) object, "$objects{$_}")) #define newSV${mangled}_ornull(object) (((object) == NULL) ? &PL_sv_undef : newSV$mangled(object)) EOS if (exists $backend_guards{$type}) { print HEADER "#endif /* $backend_guards{$type} */\n"; } } # ------------------------------------------------------------------- # print HEADER "\n/* structs */\n\n"; foreach (keys %structs) { /^(.+) \*/; my $type = $1; my $mangled = mangle ($type); print HEADER <<"EOS"; typedef $type ${type}_ornull; #define Sv$mangled(sv) (($type *) cairo_struct_from_sv (sv, "$structs{$_}")) #define Sv${mangled}_ornull(sv) (((sv) && SvOK (sv)) ? Sv$mangled(sv) : NULL) #define newSV$mangled(struct) (cairo_struct_to_sv (($type *) struct, "$structs{$_}")) #define newSV${mangled}_ornull(struct) (((struct) == NULL) ? &PL_sv_undef : newSV$mangled(struct)) EOS } # ------------------------------------------------------------------- # print HEADER "\n/* enums */\n\n"; foreach my $type (keys %enums) { my $mangled = mangle ($type); my $name = name ($type); next unless @{$enums{$type}}; if (exists $enum_guards{$type}) { print HEADER "#ifdef $enum_guards{$type}\n"; } print HEADER <<"EOS"; int cairo_${name}_from_sv (SV * $name); SV * cairo_${name}_to_sv (int val); #define Sv$mangled(sv) (cairo_${name}_from_sv (sv)) #define newSV$mangled(val) (cairo_${name}_to_sv (val)) EOS if (exists $enum_guards{$type}) { print HEADER "#endif /* $enum_guards{$type} */\n"; } } close HEADER; return ($cairo_perl); } # --------------------------------------------------------------------------- # sub do_enums { my %enums = %{shift ()}; my %guards = %{shift ()}; my $cairo_enums = 'cairo-perl-enums.c'; open ENUMS, '>', $cairo_enums or die "unable to open ($cairo_enums) for output"; print ENUMS " /* * This file was automatically generated. Do not edit. */ #include "; sub canonicalize { my ($name, $prefix) = @_; $name =~ s/$prefix//; $name =~ tr/_/-/; $name = lc ($name); return $name; } sub if_tree_from { my @enums = @_; my $prefix = shift @enums; my $full = shift @enums; my $name = canonicalize($full, $prefix); # +1 so that strncmp also looks at the trailing \0, and discerns # 'color' and 'color-alpha', for example. my $len = length ($name) + 1; my $str = <<"EOS"; if (strncmp (str, "$name", $len) == 0) return $full; EOS foreach $full (@enums) { my $name = canonicalize($full, $prefix); $len = length ($name); $str .= <<"EOS"; else if (strncmp (str, "$name", $len) == 0) return $full; EOS } $str; } sub if_tree_to { my @enums = @_; my $prefix = shift @enums; my $full = shift @enums; my $name = canonicalize($full, $prefix); my $str = <<"EOS"; if (val == $full) return newSVpv ("$name", 0); EOS foreach $full (@enums) { my $name = canonicalize($full, $prefix); $str .= <<"EOS"; else if (val == $full) return newSVpv ("$name", 0); EOS } $str; } foreach my $type (keys %enums) { my $name = name($type); my @enum_values = @{$enums{$type}}; next unless @enum_values; my $value_list = join ", ", map { canonicalize($_, $enum_values[0]) } @enum_values[1..$#enum_values]; my $tree_from = if_tree_from (@enum_values); my $tree_to = if_tree_to (@enum_values); if (exists $guards{$type}) { print ENUMS "#ifdef $guards{$type}\n\n"; } print ENUMS <<"EOS"; int cairo_${name}_from_sv (SV * $name) { char * str = SvPV_nolen ($name); $tree_from croak ("`%s' is not a valid $type value; valid values are: $value_list", str); return 0; } SV * cairo_${name}_to_sv (int val) { $tree_to warn ("unknown $type value %d encountered", val); return &PL_sv_undef; } EOS if (exists $guards{$type}) { print ENUMS "#endif /* $guards{$type} */\n"; } } close ENUMS; } 1;