File Coverage

blib/lib/xsub.pm
Criterion Covered Total %
statement 75 93 80.6
branch 21 48 43.7
condition 7 18 38.8
subroutine 5 5 100.0
pod n/a
total 108 164 65.8


line stmt bran cond sub pod time code
1             package xsub;
2             $VERSION = 1.0;
3              
4             my %XSUB;
5              
6             sub import {
7 35     35   44 my $p = shift;
8              
9 35         200 my ($package, $file, $line) = caller;
10              
11 35         52 my $source = pop;
12 35         36 my $name = shift;
13 35 100 66     269 my $prototype = @_ && $_[0] !~ /^:/ ? shift : undef;
14 35         59 my $attributes = [@_];
15 35         59 s/^:// for @$attributes;
16              
17 35         217 my $xs = bless {
18             name => $name,
19             source => $source,
20             package => $package,
21             file => $file,
22             line => $line,
23             prototype => $prototype,
24             attributes => $attributes,
25             }, $p;
26              
27 35 100       76 if ($name) {
28 34 50       68 my $pr = defined($prototype) ? "($prototype)" : "";
29 34         1203 eval "package $package; sub $name $pr";
30 34 50       100 $@ and die $@;
31             }
32              
33 35         38 local *XSUB = \@{$XSUB{$file}};
  35         87  
34 35         1977 push @XSUB, $xs;
35             }
36              
37             sub _reindent($$) {
38 37     37   48 my $v = ' ' x shift;
39 37         135 my @l = split /\n/, $_[0];
40              
41 37         51 my $i = 0;
42 37   66     215 $i++ while $i < @l && $l[$i] eq '';
43 37 50 33     176 $i < @l && $l[$i] =~ m/^(\s+)/ or return $_[0];
44 37         54 my $k = $1;
45              
46 37         625 s/^$k/$v/ for @l;
47 37         182 join "\n", @l, '';
48             }
49              
50             sub _unindent($) {
51 3     3   8 _reindent(0, $_[0])
52             }
53              
54             sub _compile {
55 1     1   3 my ($c, $so) = @_;
56 1         1079 my $cmd =
57             "$C{cc} $C{ccflags} -O3 $C{cccdlflags} " .
58             "-I$C{archlib}/CORE $C{lddlflags} -o $so $c";
59 1         498156 my $x = system $cmd;
60 1 50       4938 $x and die;
61 0 0       0 -e $so or die;
62             }
63              
64             sub bootstrap {
65 1     1   2 my $p = shift;
66 1         27 my ($q, $qpm) = (caller)[0, 1];
67 1         1 my ($qc, $qso);
68              
69 1         4 local *XSUB = \@{$XSUB{$qpm}};
  1         3  
70 1 50       5 defined @XSUB or return;
71              
72 1 50       35 -e $qpm or die;
73 1 50       8 $qpm =~ m/\.pm$/ or die;
74 1 50       8 ($qc = $qpm) =~ s/\.pm$/\.c/ or die;
75 1 50       7 ($qso = $qpm) =~ s/\.pm$/\.so/ or die;
76              
77 1 0 33     19 if (!-e $qso || (-M $qpm < -M $qso) || (-M __FILE__ < -M $qso)) {
      33        
78 1         3 local *XS;
79 1 50       127 open XS, '>', $qc or die;
80 1         4 my $pre = select(XS);
81              
82 1         6 print _unindent qq{
83             #include "EXTERN.h"
84             #include "perl.h"
85             #include "XSUB.h"
86              
87             #define __PACKAGE__ "$q"
88             #define undef (&PL_sv_undef)
89             #define true (&PL_sv_yes)
90             #define yes true
91             #define false (&PL_sv_no)
92             #define no false
93             #define unless(x) if (!(x))
94             #define wantarray (GIMME == G_ARRAY)
95             #define wantvoid (GIMME == G_VOID)
96             #define wantscalar (GIMME == G_SCALAR)
97             };
98              
99 1         3 print _unindent q{
100             #define _C_RETURN_AV(sv) { \
101             AV *av = (AV *)(sv); I32 n = 1 + AvFILL(av); \
102             EXTEND(SP, n); Copy(AvARRAY(av), SP + 1, n, SV *); SP += n; \
103             av_undef(av); \
104             PUTBACK; return; \
105             }
106              
107             #define _C_RETURN_SV(sv) { \
108             PUSHs(sv_2mortal(sv)); \
109             PUTBACK; return; \
110             }
111              
112             #define _C_DECLARE(name) XS(name) { \
113             dXSARGS; SP -= items; { \
114             SV *(_C_ ## name)(U32, SV **); \
115             SV *sv = (_C_ ## name)(items, &ST(0)); \
116             if (!sv) { PUTBACK; return; } \
117             if (SvTYPE(sv) == SVt_PVAV) \
118             _C_RETURN_AV(sv) \
119             else \
120             _C_RETURN_SV(sv) \
121             } \
122             } SV *_C_ ## name (UV argc, SV **argv)
123             };
124              
125 1         4 for (@XSUB) {
126 35 100       83 unless ($$_{name}) {
127 1         5 print "#line $$_{line} \"$$_{file}\"\n";
128 1         3 print _unindent($$_{source}), "\n";
129 1         4 next;
130             }
131              
132 34         77 (my $name = "XS_$$_{package}_$$_{name}") =~ s/::/__/g;
133              
134 34         36 print "\n";
135 34         47 print "_C_DECLARE($name) {\n";
136 34         85 print "#line $$_{line} \"$$_{file}\"\n";
137 34         58 print _reindent(2, $$_{source});
138 34         54 print "}\n";
139             # print "#define $$_{name} _C_$name\n";
140             }
141              
142 1         3 (my $boot_q = "boot_$q") =~ s/::/__/g;
143 1         3 print "\nXS($boot_q) {\n";
144 1         2 for (@XSUB) {
145 35 100       62 $$_{name} or next;
146 34         56 my $realname = "$$_{package}::$$_{name}";
147 34         57 (my $name = "XS_$$_{package}_$$_{name}") =~ s/::/__/g;
148              
149 34         44 my $pr = $$_{prototype};
150 34 50       142 defined $pr and $pr =~ s/\\/\\\\/g;
151              
152 34         36 print " newXS";
153 34 50       56 print "proto" if defined $pr;
154 34         49 print "(\"$realname\", $name, __FILE__";
155 34 50       65 print ", \"$pr\"" if defined $pr;
156 34         179 print ");\n";
157             }
158 1         3 print "}\n";
159              
160 1         4 select($pre);
161 1         32 close XS;
162              
163 1         8 require Config;
164 1         3 local *C = \%Config::Config;
165              
166 1         26 unlink($qso);
167 1         4 _compile($qc, $qso);
168 0           unlink($qc);
169             }
170              
171 0           require DynaLoader;
172 0 0         $qso =~ m<^/> or $qso = "./$qso";
173 0 0         my $libref = DynaLoader::dl_load_file($qso, 0) or die;
174 0           (my $boot_q = "boot_$q") =~ s/::/__/g;
175 0 0         my $symref = DynaLoader::dl_find_symbol($libref, $boot_q) or die;
176 0 0         DynaLoader::dl_install_xsub($boot_q, $symref, $qso) or die;
177              
178 0           &{$boot_q};
  0            
179              
180 0           require attributes;
181 0           for (@XSUB) {
182 0 0 0       $$_{name} && @{$$_{attributes}} or next;
  0            
183 0           for my $a (@{$$_{attributes}}) {
  0            
184 0           import attributes $$_{package}, \&{"$$_{package}::$$_{name}"}, $a;
  0            
185             }
186             }
187             }
188              
189             1