File Coverage

blib/lib/ExtUtils/XSBuilder/WrapXS.pm
Criterion Covered Total %
statement 33 824 4.0
branch 0 326 0.0
condition 0 98 0.0
subroutine 11 74 14.8
pod 18 61 29.5
total 62 1383 4.4


line stmt bran cond sub pod time code
1             package ExtUtils::XSBuilder::WrapXS;
2            
3 1     1   4107 use strict;
  1         1  
  1         35  
4 1     1   5 use warnings FATAL => 'all';
  1         2  
  1         38  
5            
6 1     1   5 use constant GvSHARED => 0; #$^V gt v5.7.0;
  1         5  
  1         67  
7            
8 1     1   5 use File::Spec ;
  1         2  
  1         19  
9 1     1   645 use ExtUtils::XSBuilder::TypeMap ();
  1         3  
  1         35  
10 1     1   11 use ExtUtils::XSBuilder::MapUtil qw(function_table structure_table callback_table);
  1         2  
  1         77  
11 1     1   981 use ExtUtils::XSBuilder::PODTemplate ;
  1         3  
  1         39  
12 1     1   6 use File::Path qw(rmtree mkpath);
  1         1  
  1         108  
13 1     1   5 use Cwd qw(fastcwd);
  1         2  
  1         48  
14 1     1   5 use Data::Dumper;
  1         2  
  1         37  
15            
16 1     1   4 use Carp qw(confess) ;
  1         1  
  1         11066  
17            
18             our $VERSION = '0.03';
19            
20             my %warnings;
21             my $verbose = 0 ;
22            
23             =pod
24            
25             =head1 NAME
26            
27             ExtUtils::XSBuilder::WrapXS - create perl XS wrappers for C functions
28            
29             =head2 DESCRIPTION
30            
31             For more information, see L
32            
33             =cut
34            
35             # ============================================================================
36            
37             sub new {
38 0     0 0   my $class = shift;
39            
40 0           my $self = bless {
41             }, $class;
42            
43 0           $self -> {glue_dirs} = [$self -> xs_glue_dirs()] ;
44 0           $self -> {typemap} = $self -> new_typemap ;
45 0           $self -> {parsesource} = $self -> new_parsesource ;
46 0           $self -> {xs_includes} = $self -> xs_includes ;
47 0           $self -> {callbackno} = 1 ;
48            
49 0           for (qw(c hash)) {
50 0           my $w = "noedit_warning_$_";
51 0           my $method = $w ;
52 0           $self->{$w} = $self->$method();
53             }
54            
55 0           $self->typemap->get;
56 0           $self;
57             }
58            
59             # ============================================================================
60            
61             sub classname {
62 0   0 0 0   my $self = shift || __PACKAGE__;
63 0 0         ref($self) || $self;
64             }
65            
66             # ============================================================================
67            
68             sub calls_trace {
69 0     0 0   my $frame = 1;
70 0           my $trace = '';
71            
72 0           while (1) {
73 0           my($package, $filename, $line) = caller($frame);
74 0 0         last unless $filename;
75 0           $trace .= "$frame. $filename:$line\n";
76 0           $frame++;
77             }
78            
79 0           return $trace;
80             }
81            
82             # ============================================================================
83            
84             sub noedit_warning_c {
85 0     0 0   my $class = classname(shift);
86 0           my $warning = \$warnings{C}->{$class};
87 0 0         return $$warning if $$warning;
88 0           my $v = join '/', $class, $class->VERSION;
89 0           my $trace = calls_trace();
90 0           $trace =~ s/^/ * /mg;
91 0           $$warning = <
92            
93             /*
94             * *********** WARNING **************
95             * This file generated by $v
96             * Any changes made here will be lost
97             * ***********************************
98             $trace */
99            
100             EOF
101             }
102            
103             # ============================================================================
104            
105             #this is named hash after the `#' character
106             #rather than named perl, since #comments are used
107             #non-Perl files, e.g. Makefile, typemap, etc.
108             sub noedit_warning_hash {
109 0     0 0   my $class = classname(shift);
110 0           my $warning = \$warnings{hash}->{$class};
111 0 0         return $$warning if $$warning;
112 0           ($$warning = noedit_warning_c($class)) =~ s/^/\# /mg;
113 0           $$warning;
114             }
115            
116            
117             # ============================================================================
118             =pod
119            
120             =head2 new_parsesource (o)
121            
122             Returns an array ref of new ParseSource objects for all source files that
123             should be used to generate XS files
124            
125             =cut
126            
127 0     0 1   sub new_parsesource { [ ExtUtils::XSBuilder::ParseSource->new ] }
128            
129            
130             # ============================================================================
131             =pod
132            
133             =head2 new_typemap (o)
134            
135             Returns a new typemap object
136            
137             =cut
138            
139 0     0 1   sub new_typemap { ExtUtils::XSBuilder::TypeMap->new (shift) }
140            
141             # ============================================================================
142             =pod
143            
144             =head2 new_podtemplate (o)
145            
146             Returns a new podtemplate object
147            
148             =cut
149            
150 0     0 1   sub new_podtemplate { ExtUtils::XSBuilder::PODTemplate->new }
151            
152             # ============================================================================
153             =pod
154            
155             =head2 xs_includes (o)
156            
157             Returns a list of XS include files.
158            
159             Default: use all include files that C returns, but
160             strip path info
161            
162             =cut
163            
164             sub xs_includes
165             {
166 0     0 1   my $self = shift ;
167 0           my $parsesource = $self -> parsesource_objects ;
168            
169 0           my @includes ;
170             my @paths ;
171 0           foreach my $src (@$parsesource) {
172 0           push @includes, @{ $src -> find_includes } ;
  0            
173 0           push @paths, @{ $src -> include_paths } ;
  0            
174             }
175            
176 0           foreach (@paths)
177             {
178 0           s#(\\|/)$## ;
179 0           s#\\#/# ;
180             }
181 0           foreach (@includes)
182             {
183 0           s#\\#/# ;
184             }
185            
186            
187             # strip include paths
188 0           foreach my $file (@includes)
189             {
190 0           foreach my $path (@paths)
191             {
192 0 0         if ($file =~ /^\Q$path\E(\/|\\)(.*?)$/i)
193             {
194 0           $file = $2 ;
195 0           last ;
196             }
197             }
198             }
199            
200            
201 0           my %includes = map { $_ => 1 } @includes ;
  0            
202 0           my $fixup1 = $self -> h_filename_prefix . 'preperl.h' ;
203 0           my $fixup2 = $self -> h_filename_prefix . 'postperl.h' ;
204            
205            
206            
207             return [
208 0 0         keys %includes,
    0          
209             -f $self -> xs_include_dir . '/'. $fixup1?$fixup1:(),
210             'EXTERN.h', 'perl.h', 'XSUB.h',
211             -f $self -> xs_include_dir . '/'. $fixup2?$fixup2:(),
212             $self -> h_filename_prefix . 'sv_convert.h',
213             $self -> h_filename_prefix . 'typedefs.h',
214             ] ;
215             }
216            
217            
218            
219             # ============================================================================
220             =pod
221            
222             =head2 xs_glue_dirs (o)
223            
224             Returns a list of additional XS glue directories to seach for maps in.
225            
226             =cut
227            
228            
229             sub xs_glue_dirs {
230 0     0 1   () ;
231             }
232            
233            
234             # ============================================================================
235             =pod
236            
237             =head2 xs_base_dir (o)
238            
239             Returns a directory which serves as a base for other directories.
240            
241             Default: C<'.'>
242            
243             =cut
244            
245            
246 0     0 1   sub xs_base_dir { '.' } ;
247            
248            
249            
250             # ============================================================================
251             =pod
252            
253             =head2 xs_map_dir (o)
254            
255             Returns the directory to search for map files in
256            
257             Default: C</xsbuilder/maps>
258            
259             =cut
260            
261            
262 0     0 1   sub xs_map_dir { File::Spec -> catdir ($_[0] -> xs_base_dir, 'xsbuilder', 'maps') } ;
263            
264             # ============================================================================
265             =pod
266            
267             =head2 xs_incsrc_dir (o)
268            
269             Returns the directory to search for files to include into the source. For
270             example, C</Apache/DAV/Resource/Resource_pm> will be included into
271             the C module.
272            
273             Default: C</xsbuilder>
274            
275            
276             =cut
277            
278            
279 0     0 1   sub xs_incsrc_dir { File::Spec -> catdir ($_[0] -> xs_base_dir, 'xsbuilder') ; } ;
280            
281             # ============================================================================
282             =pod
283            
284             =head2 xs_include_dir (o)
285            
286             Returns a directory to search for include files for pm and XS
287            
288             Default: C</xsinclude>
289            
290             =cut
291            
292            
293 0     0 1   sub xs_include_dir { File::Spec -> catdir ($_[0] -> xs_base_dir, 'xsinclude') ; } ;
294            
295             # ============================================================================
296             =pod
297            
298             =head2 xs_target_dir (o)
299            
300             Returns the directory to write generated XS and header files in
301            
302             Default: C</xs>
303            
304             =cut
305            
306            
307 0     0 1   sub xs_target_dir { File::Spec -> catdir ($_[0] -> xs_base_dir, 'xs') ; }
308            
309            
310             # ============================================================================
311            
312 0     0 0   sub typemap { shift->{typemap} }
313            
314             # ============================================================================
315            
316 0 0   0 0   sub includes { shift->{xs_includes} || [] }
317            
318             # ============================================================================
319            
320 0     0 0   sub parsesource_objects { shift->{parsesource} }
321            
322             # ============================================================================
323            
324             sub function_list {
325 0     0 0   my $self = shift;
326 0           my(@list) = @{ function_table($self) };
  0            
327            
328 0           while (my($name, $val) = each %{ $self->typemap->function_map }) {
  0            
329             #entries that do not exist in C::Scan generated tables
330 0 0         next unless $name =~ /^DEFINE_/;
331 0           push @list, $val;
332             }
333            
334 0           return \@list;
335             }
336            
337             # ============================================================================
338            
339             sub callback_list {
340 0     0 0   my $self = shift;
341 0           my(@list) = @{ callback_table($self) };
  0            
342            
343 0           while (my($name, $val) = each %{ $self->typemap->callback_map }) {
  0            
344             #entries that do not exist in C::Scan generated tables
345 0 0         next unless $name =~ /^DEFINE_/;
346 0           push @list, $val;
347             }
348            
349 0           return \@list;
350             }
351            
352             # ============================================================================
353            
354             sub get_callback_function {
355 0     0 0   my ($self, $func, $struct, $elt) = @_ ;
356            
357 0           my $myprefix = $self -> my_xs_prefix ;
358 0           my $n ;
359 0           $elt -> {callbackno} = $n = $self -> {callbackno}++ ;
360 0           my $structelt = $elt -> {name} ;
361 0           my $class = $struct -> {class} ;
362 0           my $cclass = $self -> cname($class) ;
363            
364 0           my($name, $args, $retargs, $return_type, $orig_args, $userdataarg) =
365 0           @{ $func } { qw(perl_name args retargs return_type orig_args userdataarg) };
366            
367 0   0       $struct -> {staticcnt} ||= 4 ;
368 0           my $staticcnt = $struct -> {staticcnt} ;
369             #print "get_callback_function: ", Data::Dumper -> Dump([$func]), "\n" ;
370            
371 0           my $code = "\n/* --- $class -> $structelt --- */\n\n" ;
372 0           my $cbname = "${myprefix}cb_${cclass}__$structelt" ;
373 0           my %retargs = map { $_->{name} => $_ } @$retargs ;
  0            
374 0           my %args = map { $_->{name} => $_ } @$args ;
  0            
375 0 0 0       my @args = map { my $name = /^(?:\*|&)(.*?)$/?$1:$_ ; ($args{$name}{rtype} || $retargs{$name}{rtype}) . (/^&/?" * $name":" $name") } @$orig_args ;
  0 0          
  0            
376 0           $return_type = $self -> cname($return_type) ;
377 0   0       my $return_class = $self -> typemap -> map_class ($return_type) || $return_type;
378 0 0         if ($return_class =~ / /)
379             {
380 0           print "ERROR: return class '$return_class' contains spaces" ;
381             }
382            
383 0           my $desttype = 'CV' ;
384 0 0         if ($structelt)
385             {
386 0           $desttype = 'SV' ;
387             }
388            
389 0 0         my $numret = $return_type eq 'void'?0:1 ;
390 0           $numret += @$retargs ;
391 0 0         my $callflags = $numret == 0?'G_VOID':$numret == 1?'G_SCALAR':'G_ARRAY' ;
    0          
392            
393 0           $code .= qq[
394            
395             static $return_type $cbname (] . join (',', "$desttype * __cbdest", @args) . qq[)
396             {
397             ] ;
398 0 0 0       $code .= " $return_type __retval ;\n" if ($return_type && $return_type ne 'void') ;
399 0 0         $code .= " SV * __retsv ;\n" if ($numret) ;
400 0           $code .= qq[
401             int __cnt ;
402            
403             dSP ;
404             ENTER ;
405             SAVETMPS ;
406             PUSHMARK(SP) ;
407             ];
408            
409 0 0         if ($structelt)
410             {
411 0           $code .= " PUSHs(__cbdest) ;\n" ;
412             }
413            
414 0           foreach (@$orig_args) {
415 0 0         my $type = /^(?:\*|\&)(.*?)$/?$1:$_ ;
416 0 0         my $name = /^\*(.*?)$/?"&$1":$_ ;
417 0 0         next if ($retargs{$type}{class}) ;
418 0 0 0       if (!$args{$type}{class} && !$args{$type}{type})
419             {
420 0           print "WARNING: unknown type for argument '$name' in struct member '$structelt'\n" ;
421 0           print Dumper ($args) ;
422 0           next ;
423             }
424 0   0       my $class = $args{$type}{class} || $args{$type}{type} ;
425 0 0         if ($class =~/\s/)
426             {
427 0           print "WARNING: type '$class' for argument '$name' in struct member '$structelt' contains spaces\n" ;
428 0           print Dumper ($args) ;
429 0           next ;
430             }
431            
432 0           $code .= ' PUSHs(' . $self -> convert_2obj ($class, $name) . ") ;\n" ;
433             }
434            
435 0           $code .= qq[
436             PUTBACK ;
437             ] ;
438            
439 0 0         if ($structelt)
440             {
441 0           $code .= " __cnt = perl_call_method(\"cb_$structelt\", $callflags) ;\n" ;
442             }
443             else
444             {
445 0           $code .= " __cnt = perl_call_sv(__cbdest, $callflags) ;\n" ;
446             }
447            
448 0 0         $code .= qq[
449            
450             if (__cnt != $numret)
451             croak (\"$cbname expected $numret return values\") ;
452             ] if ($numret > 0) ;
453            
454 0           $code .= qq[
455             SPAGAIN ;
456             ] ;
457            
458 0 0 0       if ($return_type && $return_type ne 'void')
459             {
460 0           $code .= " __retsv = POPs;\n" ;
461 0           $code .= ' __retval = ' . $self -> convert_sv2 ($return_type, $return_class, '__retsv') . ";\n"
462             }
463 0           foreach (@$retargs) {
464 0           $code .= " __retsv = POPs;\n" ;
465 0           $code .= " *$_->{name} = " . $self -> convert_sv2 ($_->{rtype}, $_->{class}, '__retsv') . ";\n" ;
466             }
467            
468 0           $code .= qq[
469             PUTBACK ;
470             FREETMPS ;
471             LEAVE ;
472            
473            
474             ] ;
475 0 0 0       $code .= " return __retval ;\n" if ($return_type && $return_type ne 'void') ;
476 0           $code .= qq[
477             }
478            
479             ] ;
480            
481 0 0         if (!$userdataarg) {
482 0   0       $staticcnt ||= 4 ;
483            
484 0           for (my $i = 0 ; $i < $staticcnt; $i++) {
485 0           $code .= qq[
486            
487             static $return_type ${cbname}_obj$i (] . join (',', @args) . qq[)
488             {
489             ] . ($return_type eq 'void'?'':'return') . qq[ ${cbname} (] .
490 0 0         join (',', "${myprefix}${cclass}_obj[$i]", map { /^(?:\*|\&)?(.*?)$/ } @$orig_args) . qq[) ;
491             }
492            
493             ] ;
494            
495            
496             }
497 0           $code .= "typedef $return_type (*t${cbname}_func)(" . join (',', @args) . qq") ;\n" ;
498 0           $code .= "static t${cbname}_func ${myprefix}${cbname}_func [$staticcnt] = {\n " .
499 0           join (",\n ", map { "${cbname}_obj$_" } (0..$staticcnt-1)) . "\n } ;\n\n\n" ;
500             }
501            
502 0           unshift @{ $self->{XS}->{ $func->{module} } }, {
  0            
503             code => $code,
504             class => '',
505             name => $name,
506             };
507            
508             }
509            
510            
511            
512             # ============================================================================
513            
514            
515            
516             sub get_function {
517 0     0 0   my ($self, $func) = @_ ;
518            
519 0           my $myprefix = $self -> my_xs_prefix ;
520            
521 0           my($name, $module, $class, $args, $retargs) =
522 0           @{ $func } { qw(perl_name module class args retargs) };
523            
524 0           my %retargs = map { $_->{name} => $_ } @$retargs ;
  0            
525            
526 0 0         print "get_function: ", Data::Dumper -> Dump([$func]), "\n" if ($verbose);
527             #eg ap_fputs()
528 0 0         if ($name =~ s/^DEFINE_//) {
529 0           $func->{name} =~ s/^DEFINE_//;
530            
531 0 0         if (needs_prefix($func->{name})) {
532             #e.g. DEFINE_add_output_filter
533 0           $func->{name} = make_prefix($func->{name}, $class);
534             }
535             }
536            
537 0 0         my $xs_parms = join ', ',
538 0           map { defined $_->{default} ?
539             "$_->{name}=$_->{default}" : $_->{name} } @$args;
540            
541 0           my $parms ;
542 0 0         if ($func -> {dispatch_argspec})
543             {
544 0           $parms = $func -> {dispatch_argspec} ;
545             }
546             else
547             {
548 0           ($parms = join (',', $xs_parms,
549 0           map { "\&$_->{name}" } @$retargs)) =~
550             s/=[^,]+//g; #strip defaults
551             }
552            
553 0           my $proto = join "\n",
554             (map " $_->{type} $_->{name}", @$args) ;
555            
556 0 0         my $return_type =
557             $name =~ /^DESTROY$/ ? 'void' : $func->{return_type};
558            
559 0           my $retdecl = @$retargs?(join "\n",
560 0 0         (map { my $type = $self -> cname($_->{class}) ; $type =~ s/\*$//; ' ' . $type . " $_->{name};"} @$retargs),
  0            
  0            
561             #' ' . $self -> cname($return_type) . ' RETVAL',
562             ''):'';
563            
564 0           my($dispatch, $orig_args) =
565 0           @{ $func } {qw(dispatch orig_args)};
566            
567 0 0         if ($dispatch =~ /^$myprefix/io) {
568 0           $name =~ s/^$myprefix//;
569 0           $name =~ s/^$func->{prefix}//;
570 0           push @{ $self->{newXS}->{ $module } },
  0            
571             ["$class\::$name", $dispatch];
572 0           return;
573             }
574            
575 0   0       my $passthru = @$args && $args->[0]->{name} eq '...';
576 0 0         if ($passthru) {
577 0           $parms = '...';
578 0           $proto = '';
579             }
580            
581 0           my $attrs = $self->attrs($name);
582            
583 0           my $code = <
584             $return_type
585             $name($xs_parms)
586             EOF
587 0 0         $code .= "$proto\n" if ($proto) ;
588 0 0         $code .= "$attrs\n" if ($attrs) ;
589 0 0         $code .= "PREINIT:\n$retdecl" if ($retdecl) ;
590            
591 0 0 0       if ($dispatch || $orig_args) {
592 0           my $thx = "";
593            
594 0 0         if ($dispatch) {
595 0 0         $thx = 'aTHX_ ' if $dispatch =~ /^$myprefix/i;
596 0 0 0       if ($orig_args && !$func -> {dispatch_argspec}) {
597 0 0         $parms = join ', ', map { $retargs{$_}?"&$_":$_} @$orig_args;
  0            
598             }
599             }
600             else {
601             ### ??? gr ### if ($orig_args and @$orig_args == @$args) {
602 0 0 0       if ($orig_args && @$orig_args) {
603             #args were reordered
604 0 0         $parms = join ', ', map { $retargs{$_}?"&$_":$_} @$orig_args;
  0            
605             }
606            
607 0           $dispatch = $func->{name};
608             }
609            
610 0 0         if ($passthru) {
611 0   0       $thx ||= 'aTHX_ ';
612 0           $parms = 'items, MARK+1, SP';
613             }
614            
615 0 0         my $retval = $return_type eq 'void' ?
616             ["", ""] : ["RETVAL = ", "OUTPUT:\n RETVAL\n"];
617            
618 0 0         my $retnum = $retdecl?scalar(@$retargs) + ($return_type eq 'void' ?0:1):0 ;
    0          
619 0 0         $code .= $retdecl?"PPCODE:":"CODE:" ;
620 0           $code .= "\n $retval->[0]$dispatch($thx$parms);\n" ;
621 0 0         if ($retdecl) {
622 0   0       my $retclass = $self -> typemap -> map_class ($return_type) || $return_type ;
623 0 0         if ($retclass =~ / /)
624             {
625 0           print "ERROR: return class '$retclass' contains spaces" ;
626             }
627 0           $code .= " XSprePUSH;\n" ;
628 0           $code .= " EXTEND(SP, $retnum) ;\n" ;
629 0           $code .= ' PUSHs(' . $self -> convert_2obj ($retclass, 'RETVAL') . ") ;\n" ;
630 0           foreach (@$retargs) {
631 0 0         if ($_->{class} =~ / /)
632             {
633 0           print "ERROR: $_->{class} contains spaces; retargs = ", Dumper ($_) ;
634             }
635 0           $code .= ' PUSHs(' . $self -> convert_2obj ($_->{class}, $_->{name}) . ") ;\n" ;
636             }
637             }
638             else {
639 0           $code .= "$retval->[1]\n" ;
640             }
641             }
642            
643 0           $code .= "\n" ;
644            
645 0           $func->{code} = $code;
646 0           push @{ $self->{XS}->{ $module } }, $func;
  0            
647             }
648            
649             # ============================================================================
650            
651            
652             sub get_functions {
653 0     0 0   my $self = shift;
654            
655 0           my $typemap = $self->typemap;
656 0           my %seen ;
657 0           for my $entry (@{ $self->function_list() }) {
  0            
658             #print "get_func ", Dumper ($entry) ;
659 0           my $func = $typemap->map_function($entry);
660             #print "FAILED to map $entry->{name}\n" unless $func;
661 0 0         next unless $func;
662 0 0         print "WARNING: Duplicate function: $entry->{name}\n" if ($seen{$entry->{name}}++) ;
663 0           $self -> get_function ($func) ;
664             }
665             }
666            
667            
668             # ============================================================================
669            
670             sub get_value {
671 0     0 0   my $e = shift;
672 0           my $val = 'val';
673            
674 0 0         if ($e->{class} eq 'PV') {
675 0 0         if (my $pool = $e->{pool}) {
676 0           $pool .= '(obj)';
677 0           $val = "((ST(1) == &PL_sv_undef) ? NULL :
678             apr_pstrndup($pool, val, val_len))"
679             }
680             }
681            
682 0           return $val;
683             }
684             # ============================================================================
685            
686             sub get_structure_callback_init {
687 0     0 0   my ($self, $class, $struct) = @_ ;
688            
689 0           my $cclass = $self -> cname($class) ;
690            
691 0           my $myprefix = $self -> my_xs_prefix ;
692 0           my $staticcnt = $struct -> {staticcnt} ;
693            
694 0           my $cnv = $self -> convert_sv2 ($cclass, $class, 'obj') ;
695 0           my $code = qq[
696            
697             void
698             init_callbacks (obj, val=NULL)
699             SV * obj
700             SV * val
701             PREINIT:
702             int n = -1 ;
703             int i ;
704             $cclass cobj = $cnv ;
705             SV * ref ;
706             SV * perl_obj ;
707             CODE:
708             if (items > 1)
709             obj = val ;
710            
711             perl_obj = SvRV(obj) ;
712             ref = newRV_noinc(perl_obj) ;
713            
714             for (i=0;i < $staticcnt;i++)
715             {
716             if ($myprefix${cclass}_obj[i] == ref)
717             {
718             n = i ;
719             break ;
720             }
721             }
722            
723             if (n < 0)
724             for (i=0;i < $staticcnt;i++)
725             {
726             if ($myprefix${cclass}_obj[i] == NULL)
727             {
728             n = i ;
729             break ;
730             }
731             }
732            
733             if (n < 0)
734             croak ("Limit for concurrent object callbacks reached for $class. Limit is $staticcnt") ;
735            
736             $myprefix${cclass}_obj[n] = ref ;
737             ] ;
738            
739            
740 0           foreach my $e (@{ $struct->{elts} }) {
  0            
741 0 0         if ($e -> {callback}) {
742 0           my $cbname = "${myprefix}cb_${cclass}__$e->{name}" ;
743 0           $code .= " cobj -> $e->{name} = ${myprefix}${cbname}_func[n] ;\n" ;
744             }
745             }
746 0           $code .= qq[
747            
748             ] ;
749            
750 0           my $ccode = "static SV * ${myprefix}${cclass}_obj[$staticcnt] ;\n\n" ;
751            
752            
753 0           push @{ $self->{XS}->{ $struct->{module} } }, {
  0            
754             code => $code,
755             class => $class,
756             name => 'init_callbacks',
757             };
758            
759 0           unshift @{ $self->{XS}->{ $struct->{module} } }, {
  0            
760             code => $ccode,
761             class => '',
762             name => 'init_callbacks',
763             };
764            
765             }
766            
767             # ============================================================================
768            
769             sub get_structure_new {
770 0     0 0   my ($self, $class, $struct) = @_ ;
771            
772 0           my $cclass = $self -> cname($class) ;
773 0           my $cnvprefix = $self -> my_cnv_prefix ;
774 0   0       my $alloc = $struct -> {alloc} || 'malloc(sizeof(*cobj))' ;
775 0           my $code = qq[
776            
777             SV *
778             new (class,initializer=NULL)
779             char * class
780             SV * initializer
781             PREINIT:
782             SV * svobj ;
783             $cclass cobj ;
784             SV * tmpsv ;
785             CODE:
786             ${cnvprefix}${cclass}_create_obj(cobj,svobj,RETVAL,$alloc) ;
787            
788             if (initializer) {
789             if (!SvROK(initializer) || !(tmpsv = SvRV(initializer)))
790             croak ("initializer for ${class}::new is not a reference") ;
791            
792             if (SvTYPE(tmpsv) == SVt_PVHV || SvTYPE(tmpsv) == SVt_PVMG)
793             ${cclass}_new_init (aTHX_ cobj, tmpsv, 0) ;
794             else if (SvTYPE(tmpsv) == SVt_PVAV) {
795             int i ;
796             SvGROW(svobj, sizeof (*cobj) * av_len((AV *)tmpsv)) ;
797             for (i = 0; i <= av_len((AV *)tmpsv); i++) {
798             SV * * itemrv = av_fetch((AV *)tmpsv, i, 0) ;
799             SV * item ;
800             if (!itemrv || !*itemrv || !SvROK(*itemrv) || !(item = SvRV(*itemrv)))
801             croak ("array element of initializer for ${class}::new is not a reference") ;
802             ${cclass}_new_init (aTHX_ &cobj[i], item, 1) ;
803             }
804             }
805             else {
806             croak ("initializer for ${class}::new is not a hash/array/object reference") ;
807             }
808             }
809             OUTPUT:
810             RETVAL
811            
812             ] ;
813            
814            
815 0           my $c_code = qq[
816            
817             void ${cclass}_new_init (pTHX_ $cclass obj, SV * item, int overwrite) {
818            
819             SV * * tmpsv ;
820            
821             if (SvTYPE(item) == SVt_PVMG)
822             memcpy (obj, (void *)SvIVX(item), sizeof (*obj)) ;
823             else if (SvTYPE(item) == SVt_PVHV) {
824             ] ;
825 0           foreach my $e (@{ $struct->{elts} }) {
  0            
826 0 0 0       if ($e -> {name} =~ /^(.*?)\[(.*?)\]$/) {
    0          
827 0           my $strncpy = $2 ;
828 0           my $name = $1 ;
829 0           my $perl_name ;
830 0           ($perl_name = $e -> {perl_name}) =~ s/\[.*?\]$// ;
831 0           $c_code .= " if ((tmpsv = hv_fetch((HV *)item, \"$perl_name\", sizeof(\"$perl_name\") - 1, 0)) || overwrite) {\n" ;
832 0           $c_code .= " STRLEN l = 0;\n" ;
833 0           $c_code .= " if (tmpsv) {\n" ;
834 0           $c_code .= " char * s = SvPV(*tmpsv,l) ;\n" ;
835 0           $c_code .= " if (l > ($strncpy)-1) l = ($strncpy) - 1 ;\n" ;
836 0           $c_code .= " strncpy(obj->$name, s, l) ;\n" ;
837 0           $c_code .= " }\n" ;
838 0           $c_code .= " obj->$name\[l] = '\\0';\n" ;
839 0           $c_code .= " }\n" ;
840             } elsif (($e -> {class} !~ /::/) || ($e -> {rtype} =~ /\*$/)) {
841 0           $c_code .= " if ((tmpsv = hv_fetch((HV *)item, \"$e->{perl_name}\", sizeof(\"$e->{perl_name}\") - 1, 0)) || overwrite) {\n" ;
842            
843 0 0         if ($e -> {malloc}) {
844 0           my $type = $e->{rtype} ;
845 0           my $dest = "obj -> $e->{name}" ;
846 0           my $src = 'tmpobj' ;
847 0           my $expr = eval ('"' . $e -> {malloc} . '"') ;
848 0 0         print $@ if ($@) ;
849 0           $c_code .= " $type tmpobj = (" . $self -> convert_sv2 ($e->{rtype}, $e->{class}, '(tmpsv && *tmpsv?*tmpsv:&PL_sv_undef)') . ");\n" ;
850 0           $c_code .= " if (tmpobj)\n" ;
851 0           $c_code .= " $expr;\n" ;
852 0           $c_code .= " else\n" ;
853 0           $c_code .= " $dest = NULL ;\n" ;
854             }
855             else {
856 0           $c_code .= ' ' . "obj -> $e->{name} = " . $self -> convert_sv2 ($e->{rtype}, $e->{class}, '(tmpsv && *tmpsv?*tmpsv:&PL_sv_undef)') . " ;\n" ;
857             }
858 0           $c_code .= " }\n" ;
859             }
860             }
861 0           $c_code .= qq[ ; }
862            
863             else
864             croak ("initializer for ${class}::new is not a hash or object reference") ;
865            
866             } ;
867            
868            
869             ] ;
870            
871            
872 0           push @{ $self->{XS}->{ $struct->{module} } }, {
  0            
873             code => $code,
874             class => $class,
875             name => 'new',
876             };
877            
878 0           unshift @{ $self->{XS}->{ $struct->{module} } }, {
  0            
879             code => $c_code,
880             class => '',
881             name => 'new',
882             };
883            
884             }
885            
886            
887             # ============================================================================
888            
889             sub get_structure_destroy {
890 0     0 0   my ($self, $class, $struct) = @_ ;
891            
892 0           my $cclass = $self -> cname($class) ;
893 0           my $cnvprefix = $self -> my_cnv_prefix ;
894 0           my $code = qq[
895            
896             void
897             DESTROY (obj)
898             $class obj
899             CODE:
900             ${cclass}_destroy (aTHX_ obj) ;
901            
902             ] ;
903            
904 0           my $numfree = 0 ;
905 0           my $c_code = qq[
906            
907             void ${cclass}_destroy (pTHX_ $cclass obj) {
908             ];
909            
910 0           foreach my $e (@{ $struct->{elts} }) {
  0            
911 0 0 0       if (($e -> {class} !~ /::/) || ($e -> {rtype} =~ /\*$/)) {
912 0 0         if ($e -> {free}) {
913 0           my $src = "obj -> $e->{name}" ;
914 0           my $type = $e->{rtype} ;
915 0           my $expr = eval ('"' . $e -> {free} . '"') ;
916 0 0         print $@ if ($@) ;
917 0           $c_code .= " if (obj -> $e->{name})\n" ;
918 0           $c_code .= ' ' . $expr . ";\n" ;
919 0           $numfree++ ;
920             }
921             }
922             }
923 0           $c_code .= "\n};\n\n" ;
924            
925 0 0         if ($numfree) {
926 0           push @{ $self->{XS}->{ $struct->{module} } }, {
  0            
927             code => $code,
928             class => $class,
929             name => 'destroy',
930             };
931            
932 0           unshift @{ $self->{XS}->{ $struct->{module} } }, {
  0            
933             code => $c_code,
934             class => '',
935             name => 'destroy',
936             };
937             }
938            
939             }
940            
941             # ============================================================================
942            
943             sub get_structures {
944 0     0 0   my $self = shift;
945 0           my $typemap = $self->typemap;
946 0           my $has_callbacks = 0 ;
947            
948 0           for my $entry (@{ structure_table($self) }) {
  0            
949 0   0       print 'struct ', $entry->{type} || '???', "...\n" ;
950            
951 0           my $struct = $typemap->map_structure($entry);
952 0 0         print Data::Dumper -> Dump ([$entry, $struct], ['Table Entry', 'Mapfile Entry']) if ($verbose) ;
953 0 0         if (!$struct)
954             {
955 0           print "WARNING: Struture '$entry->{type}' not found in map file\n" ;
956 0           next ;
957             }
958            
959 0           my $class = $struct->{class};
960 0           $has_callbacks = 0 ;
961            
962 0           for my $e (@{ $struct->{elts} }) {
  0            
963 0           my($name, $default, $type, $perl_name ) =
964 0           @{$e}{qw(name default type perl_name)};
965            
966 0           print " $name...\n" ;
967            
968 0 0         if ($e -> {callback}) {
969             #print "callback < ", Dumper ($e) , "\n" ;
970 0           $self -> get_function ($e -> {func}) ;
971 0           $self -> get_callback_function ($e -> {func}, $struct, $e) ;
972 0           $has_callbacks++ ;
973             }
974             else {
975 0           (my $cast = $type) =~ s/:/_/g;
976 0           my $val = get_value($e);
977            
978 0           my $type_in = $type;
979 0           my $preinit = "/*nada*/";
980 0           my $address = '' ;
981 0           my $rdonly = 0 ;
982 0           my $strncpy ;
983 0 0 0       if ($e->{class} eq 'PV' and $val ne 'val') {
    0 0        
    0          
984 0           $type_in =~ s/char/char_len/;
985 0           $preinit = "STRLEN val_len;";
986             } elsif (($e->{class} =~ /::/) && ($e -> {rtype} !~ /\*\s*$/)) {
987             # an inlined struct is read only
988 0           $rdonly = 1 ;
989 0           $address = '&' ;
990             } elsif ($name =~ /^(.*?)\[(.*?)\]$/) {
991 0           $strncpy = $2 ;
992 0           $name = $1 ;
993 0           $perl_name =~ s/\[.*?\]$// ;
994 0           $type = 'char *' ;
995 0           $type_in = 'char *' ;
996 0           $cast = 'char *' ;
997             }
998            
999 0           my $attrs = $self->attrs($name);
1000            
1001 0           my $code = <
1002             $type
1003             $perl_name(obj, val=$default)
1004             $class obj
1005             $type_in val
1006             PREINIT:
1007             $preinit
1008             $attrs
1009             CODE:
1010             RETVAL = ($cast) $address obj->$name;
1011             EOF
1012 0 0         if ($rdonly) {
1013 0           $code .= <
1014             if (items > 1) {
1015             croak (\"$name is read only\") ;
1016             }
1017             EOF
1018             }
1019             else {
1020 0           $code .= "\n if (items > 1) {\n" ;
1021 0 0         if ($e -> {malloc}) {
    0          
1022 0           my $dest = "obj->$name" ;
1023 0           my $src = $val ;
1024 0           my $type = $cast ;
1025 0           my $expr = eval ('"' . $e -> {malloc} . '"') ;
1026 0 0         print $@ if ($@) ;
1027 0           $code .= ' ' . $expr . ";\n" ;
1028             }
1029             elsif ($strncpy) {
1030 0           $code .= " strncpy(obj->$name, ($cast) $val, ($strncpy) - 1) ;\n" ;
1031 0           $code .= " obj->$name\[($strncpy)-1] = '\\0';\n" ;
1032             }
1033             else {
1034 0           $code .= " obj->$name = ($cast) $val;\n" ;
1035             }
1036 0           $code .= " }\n" ;
1037             }
1038            
1039 0           $code .= <
1040             OUTPUT:
1041             RETVAL
1042            
1043             EOF
1044 0           push @{ $self->{XS}->{ $struct->{module} } }, {
  0            
1045             code => $code,
1046             class => $class,
1047             name => $name,
1048             perl_name => $e -> {perl_name},
1049             comment => $e -> {comment},
1050             struct_member => $e,
1051             };
1052             }
1053             }
1054 0 0         $self -> get_structure_new($class, $struct) if ($struct->{has_new}) ;
1055 0 0         $self -> get_structure_destroy($class, $struct) if ($struct->{has_new}) ;
1056 0 0         $self -> get_structure_callback_init ($class, $struct) if ($has_callbacks);
1057            
1058             }
1059             }
1060            
1061             # ============================================================================
1062            
1063             sub prepare {
1064 0     0 0   my $self = shift;
1065 0           $self->{DIR} = $self -> xs_target_dir;
1066 0           $self->{XS_DIR} = $self -> xs_target_dir ;
1067            
1068 0 0         if (-e $self->{DIR}) {
1069 0           rmtree([$self->{DIR}], 1, 1);
1070             }
1071            
1072 0           mkpath [$self->{DIR}], 1, 0755;
1073             }
1074            
1075             # ============================================================================
1076            
1077             sub class_dirname {
1078 0     0 0   my($self, $class) = @_;
1079             # my($base, $sub) = split '::', $class;
1080             # return "$self->{DIR}/$base" unless $sub; #Apache | APR
1081             # return $sub if $sub eq $self->{DIR}; #WrapXS
1082             # return "$base/$sub";
1083            
1084 0           $class =~ s/::/\//g ;
1085 0           return $class ;
1086             }
1087            
1088             # ============================================================================
1089            
1090             sub class_dir {
1091 0     0 0   my($self, $class) = @_;
1092            
1093 0           my $dirname = $self->class_dirname($class);
1094             #my $dir = ($dirname =~ m:/: and $dirname !~ m:^$self->{DIR}:) ?
1095             # join('/', $self->{DIR}, $dirname) : $dirname;
1096 0           my $dir = join('/', $self->{DIR}, $dirname) ;
1097            
1098 0 0         mkpath [$dir], 1, 0755 unless -d $dir;
1099            
1100 0           $dir;
1101             }
1102            
1103             # ============================================================================
1104            
1105             sub class_file {
1106 0     0 0   my($self, $class, $file) = @_;
1107 0           join '/', $self->class_dir($class), $file;
1108             }
1109            
1110             # ============================================================================
1111            
1112             sub cname {
1113 0     0 0   my($self, $class) = @_;
1114 0 0         confess ('ERROR: class is undefined in cname') if (!defined ($class)) ;
1115 0           $class =~ s/::$// ;
1116 0           $class =~ s/:/_/g;
1117 0           $class;
1118             }
1119            
1120            
1121            
1122             # ============================================================================
1123            
1124             sub convert_2obj {
1125 0     0 0   my($self, $class, $name) = @_;
1126            
1127 0           $self -> my_cnv_prefix . $self -> cname($class) . "_2obj($name)" ;
1128             }
1129            
1130            
1131             # ============================================================================
1132            
1133             sub convert_sv2 {
1134 0     0 0   my($self, $rtype, $class, $name) = @_;
1135            
1136 0           $class =~ s/^const\s+// ;
1137 0           $class =~ s/char\s*\*/PV/ ;
1138 0           $class =~ s/SV\s*\*/SV/ ;
1139            
1140 0           return "($rtype)" . $self -> my_cnv_prefix . 'sv2_' . $self -> cname($class) . "($name)" ;
1141             }
1142            
1143            
1144             # ============================================================================
1145            
1146             sub open_class_file {
1147 0     0 0   my($self, $class, $file) = @_;
1148            
1149 0 0         if ($file =~ /^\./) {
1150 0           my $sub = (split '::', $class)[-1];
1151 0           $file = $sub . $file;
1152             }
1153            
1154 0           my $name = $self->class_file($class, $file);
1155            
1156 0 0         open my $fh, '>', $name or die "open $name: $!";
1157 0           print "writing...$name\n";
1158            
1159 0           return $fh;
1160             }
1161            
1162            
1163             # ============================================================================
1164             =pod
1165            
1166             =head2 makefilepl_text (o)
1167            
1168             Returns text for Makefile.PL
1169            
1170             =cut
1171            
1172             sub makefilepl_text {
1173 0     0 1   my($self, $class, $deps,$typemap) = @_;
1174            
1175 0           my @parts = split (/::/, $class) ;
1176 0           my $mmargspath = '../' x @parts ;
1177 0           $mmargspath .= 'mmargs.pl' ;
1178            
1179 0           my $txt = qq{
1180             $self->{noedit_warning_hash}
1181            
1182             use ExtUtils::MakeMaker ();
1183            
1184             local \$MMARGS ;
1185            
1186             if (-f '$mmargspath')
1187             {
1188             do '$mmargspath' ;
1189             die \$\@ if (\$\@) ;
1190             }
1191            
1192             \$MMARGS ||= {} ;
1193            
1194            
1195             ExtUtils::MakeMaker::WriteMakefile(
1196             'NAME' => '$class',
1197             'VERSION' => '0.01',
1198             'TYPEMAPS' => ['$typemap'],
1199             } ;
1200 0 0         $txt .= "'depend' => $deps,\n" if ($deps) ;
1201 0           $txt .= qq{
1202             \%\$MMARGS,
1203             );
1204            
1205             } ;
1206            
1207             }
1208            
1209             # ============================================================================
1210            
1211             sub write_makefilepl {
1212 0     0 0   my($self, $class) = @_;
1213            
1214 0           $self -> {makefilepls}{$class} = 1 ;
1215            
1216 0           my $fh = $self->open_class_file($class, 'Makefile.PL');
1217            
1218 0           my $includes = $self->includes;
1219 0           my @parts = split '::', $class ;
1220 0 0         my $xs = @parts?$parts[-1] . '.c':'' ;
1221 0           my $deps = {$xs => ""};
1222            
1223 0 0         if (my $mod_h = $self->mod_h($class, 1)) {
1224 0           my $abs = File::Spec -> rel2abs ($mod_h) ;
1225 0           my $rel = File::Spec -> abs2rel ($abs, $self -> class_dir ($class)) ;
1226 0           $deps->{$xs} .= " $rel";
1227             }
1228            
1229 0           local $Data::Dumper::Terse = 1;
1230 0           $deps = Dumper $deps;
1231 0 0         $deps = undef if (!$class) ;
1232            
1233 0   0       $class ||= 'WrapXS' ;
1234 0           print $fh $self -> makefilepl_text ($class, $deps, ('../' x @parts) . 'typemap') ;
1235            
1236 0           close $fh;
1237             }
1238            
1239             # ============================================================================
1240            
1241             sub write_missing_makefilepls {
1242 0     0 0   my($self, $class) = @_;
1243            
1244 0           my %classes = ('' => 1) ;
1245 0           foreach (keys %{$self -> {makefilepls}})
  0            
1246             {
1247 0           my @parts = split (/::/, $_) ;
1248 0           my $i ;
1249 0           for ($i = 0; $i < @parts; $i++)
1250             {
1251 0           $classes{join('::', @parts[0..$i])} = 1 ;
1252             }
1253             }
1254            
1255 0           foreach my $class (keys %classes)
1256             {
1257 0 0         next if ($self -> {makefilepls}{$class}) ;
1258            
1259 0           $self -> write_makefilepl ($class) ;
1260             }
1261             }
1262            
1263             # ============================================================================
1264            
1265             sub mod_h {
1266 0     0 0   my($self, $module, $complete) = @_;
1267            
1268 0           my $dirname = $self->class_dirname($module);
1269 0           my $cname = $self->cname($module);
1270 0           my $mod_h = "$dirname/$cname.h";
1271            
1272 0           for ($self -> xs_include_dir, @{ $self->{glue_dirs} }) {
  0            
1273 0           my $file = "$_/$mod_h";
1274 0 0         $mod_h = $file if $complete;
1275 0 0         return $mod_h if -e $file;
1276             }
1277            
1278 0           undef;
1279             }
1280            
1281             # ============================================================================
1282            
1283             sub mod_pm {
1284 0     0 0   my($self, $module, $complete) = @_;
1285            
1286 0           my $dirname = $self->class_dirname($module);
1287 0           my @parts = split '::', $module;
1288 0           my $mod_pm = "$dirname/$parts[-1]_pm";
1289            
1290 0           for ($self -> xs_incsrc_dir, @{ $self->{glue_dirs} }) {
  0            
1291 0           my $file = "$_/$mod_pm";
1292 0 0         $mod_pm = $file if $complete;
1293 0           print "mod_pm $mod_pm $file $complete\n" ;
1294 0 0         return $mod_pm if -e $file;
1295             }
1296            
1297 0           undef;
1298             }
1299            
1300            
1301             # ============================================================================
1302             =pod
1303            
1304             =head2 h_filename_prefix (o)
1305            
1306             Defines a prefix for generated header files
1307            
1308             Default: C<'xs_'>
1309            
1310             =cut
1311            
1312 0     0 1   sub h_filename_prefix { 'xs_' }
1313            
1314             # ============================================================================
1315             =pod
1316            
1317             =head2 my_xs_prefix (o)
1318            
1319             Defines a prefix used for all XS functions
1320            
1321             Default: C<'xs_'>
1322            
1323             =cut
1324            
1325 0     0 1   sub my_xs_prefix { 'xs_' }
1326            
1327             # ============================================================================
1328             =pod
1329            
1330             =head2 my_cnv_prefix (o)
1331            
1332             Defines a prefix used for all conversion functions/macros.
1333            
1334             Default: C
1335            
1336             =cut
1337            
1338 0     0 1   sub my_cnv_prefix { $_[0] -> my_xs_prefix }
1339            
1340             # ============================================================================
1341             =pod
1342            
1343             =head2 needs_prefix (o, name)
1344            
1345             Returns true if the passed name should be prefixed
1346            
1347             =cut
1348            
1349             sub needs_prefix {
1350 0 0   0 1   return 0 if (!$_[1]) ;
1351 0           my $pf = $_[0] -> my_xs_prefix ;
1352 0           return $_[1] !~ /^$pf/i;
1353             }
1354            
1355             # ============================================================================
1356            
1357            
1358             sub isa_str {
1359 0     0 0   my($self, $module) = @_;
1360 0           my $str = "";
1361            
1362 0 0         if (my $isa = $self->typemap->{function_map}->{isa}->{$module}) {
1363 0           while (my($sub, $base) = each %$isa) {
1364             #XXX cannot set isa in the BOOT: section because XSLoader local-ises
1365             #ISA during bootstrap
1366             # $str .= qq{ av_push(get_av("$sub\::ISA", TRUE),
1367             # newSVpv("$base",0));}
1368 0           $str .= qq{\@$sub\::ISA = '$base';\n}
1369             }
1370             }
1371            
1372 0           $str;
1373             }
1374            
1375             # ============================================================================
1376            
1377             sub boot {
1378 0     0 0   my($self, $module) = @_;
1379 0           my $str = "";
1380            
1381 0 0         if (my $boot = $self->typemap->{function_map}->{boot}->{$module}) {
1382 0           $str = ' ' . $self -> my_xs_prefix . $self->cname($module) . "_BOOT(aTHXo);\n";
1383             }
1384            
1385 0           $str;
1386             }
1387            
1388             # ============================================================================
1389            
1390             my $notshared = join '|', qw(TIEHANDLE); #not sure why yet
1391            
1392             sub attrs {
1393 0     0 0   my($self, $name) = @_;
1394 0           my $str = "";
1395 0 0         return $str if $name =~ /$notshared$/o;
1396 0           $str = " ATTRS: shared\n" if GvSHARED;
1397 0           $str;
1398             }
1399            
1400             # ============================================================================
1401            
1402             sub write_xs {
1403 0     0 0   my($self, $module, $functions) = @_;
1404            
1405 0           my $fh = $self->open_class_file($module, '.xs');
1406 0           print $fh "$self->{noedit_warning_c}\n";
1407            
1408 0           my @includes = @{ $self->includes };
  0            
1409            
1410 0 0         if (my $mod_h = $self->mod_h($module)) {
1411 0           push @includes, $mod_h;
1412             }
1413            
1414 0           for (@includes) {
1415 0           print $fh qq{\#include "$_"\n\n};
1416             }
1417            
1418 0           my $last_prefix = "";
1419 0           my $fmap = $self -> typemap -> {function_map} ;
1420 0           my $myprefix = $self -> my_xs_prefix ;
1421            
1422 0           for my $func (@$functions) {
1423 0           my $class = $func->{class};
1424 0 0         if ($class)
1425             {
1426 0           my $prefix = $func->{prefix};
1427 0 0         $last_prefix = $prefix if $prefix;
1428            
1429 0 0         if ($func->{name} =~ /^$myprefix/o) {
1430             #e.g. mpxs_Apache__RequestRec_
1431 0           my $class_prefix = $fmap -> class_c_prefix($class);
1432 0 0         if ($func->{name} =~ /$class_prefix/) {
1433 0           $prefix = $fmap -> class_xs_prefix($class);
1434             }
1435             }
1436            
1437 0 0         $prefix = $prefix ? " PREFIX = $prefix" : "";
1438 0           print $fh "MODULE = $module PACKAGE = $class $prefix\n\n";
1439             }
1440            
1441 0           print $fh $func->{code};
1442             }
1443            
1444 0 0         if (my $destructor = $self->typemap->destructor($last_prefix)) {
1445 0           my $arg = $destructor->{argspec}[0];
1446            
1447 0           print $fh <
1448             void
1449             $destructor->{name}($arg)
1450             $destructor->{class} $arg
1451            
1452             EOF
1453             }
1454            
1455 0           print $fh "PROTOTYPES: disabled\n\n";
1456 0           print $fh "BOOT:\n";
1457 0           print $fh $self->boot($module);
1458 0           print $fh " items = items; /* -Wall */\n\n";
1459            
1460 0 0         if (my $newxs = $self->{newXS}->{$module}) {
1461 0           for my $xs (@$newxs) {
1462 0           print $fh qq{ cv = newXS("$xs->[0]", $xs->[1], __FILE__);\n};
1463 0           print $fh qq{ GvSHARED_on(CvGV(cv));\n} if GvSHARED;
1464             }
1465             }
1466            
1467 0           close $fh;
1468             }
1469            
1470             # ============================================================================
1471             =pod
1472            
1473             =head2 pm_text (o, module, isa, code)
1474            
1475             Returns the text of a C<.pm> file, or undef if no C<.pm> file should be
1476             written.
1477            
1478             Default: Create a C<.pm> file which bootstraps the XS code
1479            
1480             =cut
1481            
1482             sub pm_text {
1483 0     0 1   my($self, $module, $isa, $code) = @_;
1484            
1485 0           return <
1486             $self->{noedit_warning_hash}
1487            
1488             package $module;
1489             require DynaLoader ;
1490             use strict ;
1491             use vars qw{\$VERSION \@ISA} ;
1492             $isa
1493             push \@ISA, 'DynaLoader' ;
1494             \$VERSION = '0.01';
1495             bootstrap $module \$VERSION ;
1496            
1497             $code
1498            
1499             1;
1500             __END__