1#!/usr/bin/perl
2#
3#  Usage: cd glue/perl; ../../build/xsbuilder.pl
4#
5#
6#  This script is responsible for building the
7#
8#       glue/perl/xsbuilder/tables
9#
10#  directory by parsing the header files in src/.
11
12use strict;
13use warnings FATAL => 'all';
14use File::Basename;
15use constant WIN32 => ($^O =~ /Win32/i);
16use Cwd;
17
18my $cwd = WIN32 ?
19    Win32::GetLongPathName(cwd) : cwd;
20
21$cwd =~ m{^(.+)/glue/perl$} or die "Can't find base directory";
22my $base_dir = $1;
23my $inc_dir = "$base_dir/include";
24my $mod_dir = "$base_dir/module";
25my $xs_dir = "$base_dir/glue/perl/xsbuilder";
26
27sub slurp($$)
28{
29    open my $file, $_[1] or die "Can't open $_[1]: $!";
30    read $file, $_[0], -s $file;
31}
32
33my %c_macro_cache = (
34                     XS => sub {s/XS\s*\(([^)]+)\)/void $1()/g},
35                    );
36sub c_macro
37{
38    return $c_macro_cache{"@_"} if exists $c_macro_cache{"@_"};
39
40    my ($name, $header) = @_;
41    my $src;
42    if (defined $header) {
43        slurp local $_ => "$inc_dir/$header";
44        /^#define $name\s*\(([^)]+)\)\s+(.+?[^\\])$/ms
45            or die "Can't find definition for '$name': $_";
46        my $def = $2;
47        my @args = split /\s*,\s*/, $1;
48        for (1..@args) {
49            $def =~ s/\b$args[$_-1]\b/ \$$_ /g;
50        }
51        my $args = join ',' => ('([^,)]+)') x @args;
52        $src = "sub { /^#define $name.+?[^\\\\]\$/gms +
53                      s{$name\\s*\\($args\\)}{$def}g}";
54    }
55    else {
56        $src = "sub { /^#define $name.+?[^\\\\]\$/gms +
57                      s{$name\\s*\\(([^)]+)\\)}{\$1}g}";
58    }
59    return $c_macro_cache{"@_"} = eval $src;
60}
61
62
63
64package My::ParseSource;
65use constant WIN32 => ($^O =~ /Win32/i);
66my @dirs = ("$inc_dir", "$mod_dir/apache2/", "$base_dir/glue/perl/xsbuilder");
67use base qw/ExtUtils::XSBuilder::ParseSource/;
68
69
70__PACKAGE__->run;
71
72system("touch $base_dir/glue/perl/xsbuilder") == 0
73    or die "touch $base_dir/glue/perl/xsbuilder failed: $!"
74    unless WIN32;
75
76
77sub package {'APR::Request'}
78sub unwanted_includes {[qw/apreq_config.h apreq_private_apache2.h/]}
79
80# ParseSource.pm v 0.23 bug: line 214 should read
81# my @dirs = @{$self->include_dirs};
82# for now, we override it here just to work around the bug
83
84sub find_includes {
85    my $self = shift;
86    return $self->{includes} if $self->{includes};
87    require File::Find;
88    my(@dirs) = @{$self->include_dirs};
89    unless (-d $dirs[0]) {
90        die "could not find include directory";
91    }
92    # print "Will search @dirs for include files...\n" if ($verbose) ;
93    my @includes;
94    my $unwanted = join '|', @{$self -> unwanted_includes} ;
95
96    for my $dir (@dirs) {
97        File::Find::finddepth({
98                               wanted => sub {
99                                   return unless /\.h$/;
100                                   return if ($unwanted && (/^($unwanted)/o));
101                                   my $dir = $File::Find::dir;
102                                   push @includes, "$dir/$_";
103                               },
104                               follow => not WIN32,
105                              }, $dir);
106    }
107    return $self->{includes} = $self -> sort_includes (\@includes) ;
108}
109
110sub include_dirs {\@dirs}
111
112sub preprocess
113{
114    # need to macro-expand APREQ_DECLARE et.al. so P::RD can DTRT with
115    # ExtUtils::XSBuilder::C::grammar
116
117    for ($_[1]) {
118        ::c_macro("APREQ_DECLARE", "apreq.h")->();
119        ::c_macro("APREQ_DECLARE_HOOK", "apreq_parser.h")->();
120        ::c_macro("APREQ_DECLARE_PARSER", "apreq_parser.h")->();
121        ::c_macro("APR_DECLARE")->();
122        ::c_macro("XS")-> ();
123        s/APR_INLINE//g;
124        s/static//g;
125    }
126}
127
1281;
129