File Coverage

blib/lib/Inline/CPP.pm
Criterion Covered Total %
statement 298 393 75.8
branch 114 174 65.5
condition 89 115 77.3
subroutine 36 38 94.7
pod 1 13 7.6
total 538 733 73.4


line stmt bran cond sub pod time code
1             package Inline::CPP;
2              
3 43     43   2007311 use strict;
  43         176  
  43         1429  
4 43     43   275 use warnings;
  43         99  
  43         1198  
5 43     43   807 use 5.008001;
  43         151  
6 43     43   225 use Fcntl qw( :DEFAULT :flock );
  43         124  
  43         29433  
7              
8             require Inline::C;
9             require Inline::CPP::Parser::RecDescent;
10             require Inline::CPP::Config;
11              
12             # Note: Parse::RecDescent 'require'd within get_parser().
13              
14 43     43   324 use Carp;
  43         91  
  43         4362  
15              
16             # use base doesn't work because Inline::C cannot be "use"d directly.
17             our @ISA = qw( Inline::C ); ## no critic (ISA)
18              
19             # Development releases will have a _0xx version suffix.
20             # We eval the version number to accommodate dev. version numbering, as
21             # described in perldoc perlmodstyle.
22             our $VERSION = '0.75';
23             # $VERSION = eval $VERSION; ## no critic (eval)
24              
25             my $TYPEMAP_KIND;
26             {
27 43     43   308 no warnings 'once'; ## no critic (warnings)
  43         82  
  43         2828  
28             $TYPEMAP_KIND = $Inline::CPP::Parser::RecDescent::TYPEMAP_KIND;
29             }
30              
31             #============================================================================
32             # Register Inline::CPP as an Inline language module
33             #============================================================================
34             sub register {
35 43     43   276 use Config;
  43         81  
  43         5199  
36             return {
37             language => 'CPP',
38             aliases => ['cpp', 'C++', 'c++', 'Cplusplus', 'cplusplus', 'CXX', 'cxx'],
39             type => 'compiled',
40             suffix => $Config{dlext},
41 1     1 0 2704 };
42             } ### Tested.
43              
44             #============================================================================
45             # Validate the C++ config options: Now mostly done in Inline::C
46             #============================================================================
47             sub validate {
48 87     87 0 10734978 my ($o, @config_options) = @_;
49 87         236 my ($flavor_defs, $iostream);
50              
51             { # "used only once" warning. We know it's ok.
52 43     43   283 no warnings 'once'; ## no critic (warnings)
  43         97  
  43         37193  
  87         183  
53             ## no critic (package variable)
54              
55             # Set default compiler and libraries.
56 87   66     1159 $o->{ILSM}{MAKEFILE}{CC} ||= $Inline::CPP::Config::compiler;
57 87   66     654 $o->{ILSM}{MAKEFILE}{LIBS} ||= _make_arrayref($Inline::CPP::Config::libs);
58              
59 87         223 $flavor_defs = $Inline::CPP::Config::cpp_flavor_defs; # "Standard"?
60 87         227 $iostream = $Inline::CPP::Config::iostream_fn; # iostream filename.
61             }
62              
63             # I haven't traced it out yet, but $o->{STRUCT} gets set before getting
64             # properly set from Inline::C's validate().
65 87   100     706 $o->{STRUCT} ||= {'.macros' => q{}, '.any' => 0, '.xs' => q{}, '.all' => 0,};
66              
67 87         383 _build_auto_include($o, $flavor_defs, $iostream);
68              
69             $o->{ILSM}{PRESERVE_ELLIPSIS} = 0
70 87 100       425 unless defined $o->{ILSM}{PRESERVE_ELLIPSIS};
71              
72             # Filter out the parameters we treat differently than Inline::C,
73             # forwarding unknown requests back up to Inline::C.
74 87         423 my @propagate = _handle_config_options($o, @config_options);
75 83 100       1058 $o->SUPER::validate(@propagate) if @propagate;
76              
77 82         6696 return;
78             }
79              
80              
81             sub _build_auto_include {
82 87     87   274 my ($o, $flavor_defs, $iostream) = @_;
83 87         210 my $auto_include = <<'END';
84             #define __INLINE_CPP 1
85             #ifndef bool
86             #include <%iostream%>
87             #endif
88             extern "C" {
89             #include "EXTERN.h"
90             #include "perl.h"
91             #include "XSUB.h"
92             #include "INLINE.h"
93             }
94             #ifdef bool
95             #undef bool
96             #include <%iostream%>
97             #endif
98              
99             END
100              
101 87   66     595 $o->{ILSM}{AUTO_INCLUDE} ||= $auto_include;
102 87         515 $o->{ILSM}{AUTO_INCLUDE} = $flavor_defs . $o->{ILSM}{AUTO_INCLUDE};
103              
104             # Replace %iostream% with the correct iostream library
105 87         593 $o->{ILSM}{AUTO_INCLUDE} =~ s{%iostream%}{$iostream}xg;
106 87         238 return;
107             }
108              
109              
110             sub _handle_config_options {
111 87     87   342 my ($o, @config_options) = @_;
112 87         183 my @propagate;
113              
114 87         373 while (@config_options) {
115 76         340 my ($key, $value) = (shift @config_options, shift @config_options);
116 76         354 $key = uc $key;
117 76 100 33     911 if ($key eq 'NAMESPACE') {
    100          
    100          
    50          
    50          
118 19         136 _handle_namespace_cfg_option($o, $value);
119             }
120             elsif ($key eq 'CLASSES') {
121 15         89 _handle_classes_cfg_option($o, $value);
122             }
123             elsif ($key eq 'LIBS') {
124 1         5 _handle_libs_cfg_option($o, $value);
125             }
126             elsif ($key eq 'ALTLIBS') {
127 0         0 _handle_altlibs_cfg_option($o, $value);
128             }
129             elsif ($key eq 'PRESERVE_ELLIPSIS' or $key eq 'STD_IOSTREAM') {
130 0 0 0     0 croak "Argument to $key must be 0 or 1"
131             unless $value == 0 or $value == 1;
132 0         0 $o->{ILSM}{$key} = $value;
133             }
134             else {
135 41         230 push @propagate, $key, $value;
136             }
137             }
138 83         370 return @propagate;
139             }
140              
141             sub _handle_namespace_cfg_option {
142 19     19   105 my ($o, $value) = @_;
143 19         109 $value =~ s/^::|::$//g;
144            
145             # Perl 5.12 indroduced \p{XID_Start} and \p{XID_Continue}. Prior to that
146             # we should downgrade gracefully.
147 19 50       157 my $ident = $] ge '5.0120'
148 43     43   27423 ? qr{[\p{XID_Start}_][\p{XID_Continue}_]*}
  43         687  
  43         678  
149             : qr{[\p{Alpha}_][\p{Alpha}\p{Digit}_]*};
150              
151 19 100 100     469 croak "$value is an invalid package name."
152             unless length $value == 0
153             || $value =~ m/
154             \A
155             $ident
156             (?:::$ident)*
157             \z
158             /x;
159 18   100     3525 $value ||= 'main';
160 18         117 $o->{API}{pkg} = $value;
161 18         139 return;
162             }
163              
164              
165             sub _handle_classes_cfg_option {
166 15     15   66 my ($o, $value) = @_;
167 15         83 my $ref_value = ref($value);
168 15 100 100     470 croak 'CLASSES config option is not a valid code reference or hash '
169             . 'reference of class mappings.'
170             unless (($ref_value eq 'CODE') or ($ref_value eq 'HASH'));
171              
172 14 100       72 if ($ref_value eq 'HASH') {
173 11         28 foreach my $cpp_class (keys %{$value}) {
  11         90  
174             croak "$cpp_class is not a supported C++ class."
175 18 100 33     425 unless defined $value->{$cpp_class}
      66        
176             && length $cpp_class != 0
177             && $cpp_class =~ m/[a-zA-Z]\w*/x;
178 17         60 my $perl_class = $value->{$cpp_class};
179 17 100 66     292 croak "$perl_class is not a supported Perl class."
180             unless length $perl_class != 0 && $perl_class =~ m/[a-zA-Z]\w*/x;
181             }
182             }
183              
184 12         48 $o->{API}{classes_override} = $value;
185 12         61 return;
186             }
187              
188              
189             sub _handle_libs_cfg_option {
190 1     1   3 my ($o, $value) = @_;
191 1         3 $value = _make_arrayref($value);
192 1         8 _add_libs($o, $value);
193 1         3 return;
194             }
195              
196              
197             sub _handle_altlibs_cfg_option {
198 0     0   0 my ($o, $value) = @_;
199 0         0 $value = _make_arrayref($value);
200 0         0 push @{$o->{ILSM}{MAKEFILE}{LIBS}}, q{};
  0         0  
201 0         0 _add_libs($o, $value);
202 0         0 return;
203             }
204              
205              
206             sub _make_arrayref {
207 50     50   188 my $value = shift;
208 50 50       318 $value = [$value] unless ref $value eq 'ARRAY';
209 50         238 return $value;
210             }
211              
212             sub _add_libs {
213 1     1   3 my ($o, $libs) = @_;
214 1         2 my $num = scalar @{$o->{ILSM}{MAKEFILE}{LIBS}} - 1;
  1         5  
215 1         3 $o->{ILSM}{MAKEFILE}{LIBS}[$num] .= q{ } . $_ for @{$libs};
  1         7  
216 1         6 return;
217             }
218              
219              
220             #============================================================================
221             # Print a small report if PRINT_INFO option is set
222             #============================================================================
223             sub info {
224 1     1 1 100 my $o = shift;
225 1         10 my $info = $o->SUPER::info;
226              
227 0 0       0 $o->parse unless $o->{ILSM}{parser};
228 0         0 my $data = $o->{ILSM}{parser}{data};
229              
230 0         0 my (@class, @func);
231 0 0       0 if (defined $data->{classes}) {
232 0         0 for my $class (sort @{$data->{classes}}) {
  0         0  
233             my @parents
234 0         0 = grep { $_->{thing} eq 'inherits' } @{$data->{class}{$class}};
  0         0  
  0         0  
235 0         0 push @class, "\tclass $class";
236             push @class,
237 0 0       0 (' : ' . join(', ', map { $_->{scope} . q{ } . $_->{name} } @parents))
  0         0  
238             if @parents;
239 0         0 push @class, " {\n";
240 0         0 for my $thing (sort { $a->{name} cmp $b->{name} }
  0         0  
241 0         0 @{$data->{class}{$class}})
242             {
243 0         0 my ($name, $scope, $type) = @{$thing}{qw(name scope thing)};
  0         0  
244 0 0 0     0 next unless $scope eq 'public' and $type eq 'method';
245             next
246 0 0       0 unless $o->check_type($thing, $name eq $class, $name eq "~$class",);
247 0   0     0 my $rtype = $thing->{rtype} || q{};
248 0 0       0 push @class, "\t\t$rtype" . ($rtype ? q{ } : q{});
249 0         0 push @class, $class . "::$name(";
250 0         0 my @args = grep { $_->{name} ne '...' } @{$thing->{args}};
  0         0  
  0         0  
251 0         0 my $ellipsis = (scalar @{$thing->{args}} - scalar @args) != 0;
  0         0  
252 0 0       0 push @class, join ', ', (map {"$_->{type} $_->{name}"} @args),
  0         0  
253             $ellipsis ? '...' : ();
254 0         0 push @class, ");\n";
255             }
256 0         0 push @class, "\t};\n";
257             }
258             }
259 0 0       0 if (defined $data->{functions}) {
260 0         0 for my $function (sort @{$data->{functions}}) {
  0         0  
261 0         0 my $func = $data->{function}{$function};
262 0 0       0 next if $function =~ m/::/x;
263 0 0       0 next unless $o->check_type($func, 0, 0);
264 0         0 push @func, "\t" . $func->{rtype} . q{ };
265 0         0 push @func, $func->{name} . '(';
266 0         0 my @args = grep { $_->{name} ne '...' } @{$func->{args}};
  0         0  
  0         0  
267 0         0 my $ellipsis = (scalar @{$func->{args}} - scalar @args) != 0;
  0         0  
268 0 0       0 push @func, join ', ', (map {"$_->{type} $_->{name}"} @args),
  0         0  
269             $ellipsis ? '...' : ();
270 0         0 push @func, ");\n";
271             }
272             }
273              
274             # Report:
275             {
276 0         0 local $" = q{};
  0         0  
277 0 0       0 $info .= "The following classes have been bound to Perl:\n@class\n"
278             if @class;
279 0 0       0 $info .= "The following functions have been bound to Perl:\n@func\n"
280             if @func;
281             }
282 0 0       0 $info .= Inline::Struct::info($o) if $o->{STRUCT}{'.any'};
283 0         0 return $info;
284             }
285              
286             #============================================================================
287             # Generate a C++ parser
288             #============================================================================
289             sub get_parser {
290 44     44 0 389028 my $o = shift;
291 44         296 return Inline::CPP::Parser::RecDescent::get_parser_recdescent($o);
292             }
293              
294             #============================================================================
295             # Intercept xs_generate and create the typemap file
296             #============================================================================
297             sub xs_generate {
298 44     44 0 1319917 my $o = shift;
299 44         391 $o->write_typemap;
300 44         349 return $o->SUPER::xs_generate;
301             }
302              
303             #============================================================================
304             # Return bindings for functions and classes
305             #============================================================================
306             sub xs_bindings {
307 44     44 0 1777 my $o = shift;
308              
309             # What is modfname, and why are we taking it from a slice but not using it?
310 44         121 my ($pkg, $module) = @{$o->{API}}{qw(pkg module)};
  44         334  
311 44         177 my $data = $o->{ILSM}{parser}{data};
312 44         109 my @XS;
313              
314             warn "Warning: No Inline C++ functions or classes bound to Perl\n"
315             . "Check your C++ for Inline compatibility.\n\n"
316 44 0 66     452 if !defined $data->{classes} && !defined $data->{functions} && $^W;
      33        
317 44         113 for my $class (@{$data->{classes}}) {
  44         202  
318 49         105 my $proper_pkg;
319              
320             # Possibly override package and class names
321 49 100       218 if (exists $o->{API}{classes_override}) {
322 16         57 my $ref_classes_override = ref($o->{API}{classes_override});
323 16 100       68 if ($ref_classes_override eq 'HASH') {
    50          
324 8 50       38 if (exists $o->{API}{classes_override}->{$class})
325             { # Override class name only
326 8         54 $proper_pkg = $pkg . '::' . $o->{API}{classes_override}->{$class};
327             }
328             else {
329             # Do not override package or class names
330 0         0 $proper_pkg = $pkg . '::' . $class;
331             }
332             }
333             elsif ($ref_classes_override eq 'CODE')
334             {
335             # Override both package and class names
336 8         13 $proper_pkg = &{$o->{API}{classes_override}}($class);
  8         31  
337 8 50       84 if ($proper_pkg eq '') { $proper_pkg = 'main'; }
  0         0  
338             }
339             }
340             else { # Do not override package or class names
341 33         163 $proper_pkg = $pkg . '::' . $class;
342             }
343              
344             # Strip main:: from packages. There cannot be a package main::Foo!
345 49         348 $proper_pkg =~ s/^main::(.+)/$1/;
346              
347             # Set up the proper namespace
348 49         373 push @XS, _build_namespace($module, $proper_pkg);
349 49         253 push @XS, _generate_member_xs_wrappers($o, $pkg, $class, $proper_pkg);
350             }
351              
352 44         252 push @XS, _remove_xs_prefixes($o, $module, $pkg);
353 44         258 push @XS, _generate_nonmember_xs_wrappers($o);
354              
355 44         118 for (@{$data->{enums}}) {
  44         250  
356              
357             # Global enums.
358 0         0 $o->{ILSM}{XS}{BOOT} .= make_enum($pkg, @{$_}{qw( name body )});
  0         0  
359             }
360 44         631 return join q{}, @XS;
361             }
362              
363              
364             # Set up the proper namespace.
365             sub _build_namespace {
366 49     49   178 my ($module, $proper_pkg) = @_;
367 49         357 return <<"END";
368              
369             MODULE = $module PACKAGE = $proper_pkg
370              
371             PROTOTYPES: DISABLE
372              
373             END
374             }
375              
376              
377             sub _generate_member_xs_wrappers {
378 49     49   181 my ($o, $pkg, $class, $proper_pkg) = @_;
379 49         100 my @XS;
380 49         214 my $data = $o->{ILSM}{parser}{data};
381 49         144 my ($ctor, $dtor, $abstract) = (0, 0, 0); ## no critic (ambiguous)
382 49         139 for my $thing (@{$data->{class}{$class}}) {
  49         333  
383 195         396 my ($name, $scope, $type) = @{$thing}{qw| name scope thing |};
  195         839  
384              
385 195         608 _handle_inheritance($o, $type, $scope, $pkg, $class, $name);
386              
387             # Get/set methods will go here:
388             # Cases we skip:
389 195   100     1255 $abstract ||= ($type eq 'method' and $thing->{abstract});
      100        
390 195 100 100     719 next if ($type eq 'method' and $thing->{abstract});
391 194 100       515 next if $scope ne 'public';
392 142 50 66     871 if ($type eq 'enum') {
    100          
393 0         0 $o->{ILSM}{XS}{BOOT} .= make_enum($proper_pkg, $name, $thing->{body});
394             }
395             elsif ($type eq 'method' and $name !~ m/operator/) {
396              
397             # generate an XS wrapper
398 130   100     507 $ctor ||= ($name eq $class);
399 130   100     613 $dtor ||= ($name eq "~$class");
400 130         448 push @XS, $o->wrap($thing, $name, $class);
401             }
402             }
403              
404             # Provide default constructor and destructor:
405 49 100 100     265 push @XS, "$class *\n${class}::new()\n\n" unless ($ctor or $abstract);
406              
407 49 100 100     338 push @XS, "void\n${class}::DESTROY()\n\n" unless ($dtor or $abstract);
408 49         241 return @XS;
409             }
410              
411              
412             # Let Perl handle inheritance.
413             sub _handle_inheritance {
414 195     195   466 my ($o, $type, $scope, $pkg, $class, $name) = @_;
415 195 100 66     706 if ($type eq 'inherits' and $scope eq 'public') {
416 9   100     48 $o->{ILSM}{XS}{BOOT} ||= q{};
417            
418 9         18 my $ISA_name;
419             my $parent;
420              
421             # Possibly override package and class names
422 9 100       29 if (exists $o->{API}{classes_override}) {
423 3         8 my $ref_classes_override = ref($o->{API}{classes_override});
424 3 50       11 if ($ref_classes_override eq 'HASH') {
    50          
425 0 0       0 if (exists $o->{API}{classes_override}->{$class})
426             { # Override class name only
427 0         0 $ISA_name = $pkg . '::' . $o->{API}{classes_override}->{$class} . '::ISA';
428 0         0 $parent = $pkg . '::' . $o->{API}{classes_override}->{$name};
429             }
430             else {
431             # Do not override package or class names
432 0         0 $ISA_name = $pkg . '::' . $class . '::ISA';
433 0         0 $parent = $pkg . '::' . $name;
434             }
435             }
436             elsif ($ref_classes_override eq 'CODE')
437             {
438             # Override both package and class names
439 3         4 $ISA_name = &{$o->{API}{classes_override}}($class) . '::ISA';
  3         10  
440 3         19 $parent = &{$o->{API}{classes_override}}($name);
  3         8  
441 3 50       17 if ($ISA_name eq '') { croak 'Have empty string for \$ISA_name, croaking' }
  0         0  
442             }
443             }
444             else { # Do not override package or class names
445 6         24 $ISA_name = $pkg . '::' . $class . '::ISA';
446 6         13 $parent = $pkg . '::' . $name;
447             }
448              
449             # Strip main:: from packages. There cannot be a package main::Foo!
450 9         40 $ISA_name =~ s/^main::(.+)/$1/;
451 9         32 $parent =~ s/^main::(.+)/$1/;
452            
453 9         51 $o->{ILSM}{XS}{BOOT} .= <<"END";
454             {
455             #ifndef get_av
456             AV *isa = perl_get_av("$ISA_name", 1);
457             #else
458             AV *isa = get_av("$ISA_name", 1);
459             #endif
460             av_push(isa, newSVpv("$parent", 0));
461             }
462             END
463             }
464 195         344 return;
465             }
466              
467              
468             sub _generate_nonmember_xs_wrappers {
469 44     44   118 my $o = shift;
470 44         145 my $data = $o->{ILSM}{parser}{data};
471 44         105 my @XS;
472 44         129 for my $function (@{$data->{functions}}) {
  44         219  
473              
474             # lose constructor defs outside class decls (and "implicit int")
475 31 100       143 next if $data->{function}{$function}{rtype} eq q{};
476 25 50       168 next if $data->{function}{$function}{rtype} =~ m/static/; #specl case
477 25 100       123 next if $function =~ m/::/x; # skip member functions.
478 16 50       74 next if $function =~ m/operator/; # and operators.
479 16         109 push @XS, $o->wrap($data->{function}{$function}, $function);
480             }
481 44         133 return @XS;
482             }
483              
484              
485             # Generate XS code to remove prefixes from function names.
486             sub _remove_xs_prefixes {
487 44     44   203 my ($o, $module, $pkg) = @_;
488             my $prefix
489 44 100       293 = ($o->{ILSM}{XS}{PREFIX} ? "PREFIX = $o->{ILSM}{XS}{PREFIX}" : q{});
490 44         310 return <<"END";
491              
492             MODULE = $module PACKAGE = $pkg $prefix
493              
494             PROTOTYPES: DISABLE
495              
496             END
497              
498             }
499              
500              
501             #============================================================================
502             # Generate an XS wrapper around anything: a C++ method or function
503             #============================================================================
504             sub wrap {
505 146     146 0 401 my ($o, $thing, $name, $class) = @_;
506 146   100     465 $class ||= q{};
507 146         293 my $t = q{ } x 4; # indents in 4-space increments.
508 146         235 my (@XS, @PREINIT, @CODE);
509              
510 146         460 my ($XS, $ctor, $dtor) = _map_subnames_cpp_to_perl($thing, $name, $class);
511              
512 146         345 push @XS, $XS;
513              
514 146 50       509 return q{} unless $o->check_type($thing, $ctor, $dtor);
515              
516             # Filter out optional subroutine arguments
517 146         304 my (@args, @opts, $ellipsis, $void);
518              
519 146 100       223 $_->{optional} ? push @opts, $_ : push @args, $_ for @{$thing->{args}};
  146         440  
520              
521 146 100 100     590 $ellipsis = pop @args if (@args and $args[-1]{name} eq '...');
522              
523 146   100     709 $void = ($thing->{rtype} and $thing->{rtype} eq 'void');
524              
525             push @XS, join q{},
526             (
527             '(',
528             join(', ',
529 146 100 100     996 (map { $_->{name} } @args),
  28         202  
530             (scalar @opts or $ellipsis) ? '...' : ()),
531             ")\n",
532             );
533              
534             # Declare the non-optional arguments for XS type-checking
535 146         472 push @XS, "\t$_->{type}\t$_->{name}\n" for @args;
536              
537             # Wrap "complicated" subs in stack-checking code
538 146 100 100     789 if ($void or $ellipsis) {
539 8         19 push @PREINIT, "\tI32 *\t__temp_markstack_ptr;\n";
540 8         19 push @CODE, "\t__temp_markstack_ptr = PL_markstack_ptr++;\n";
541             }
542              
543 146 100 66     979 if (@opts) {
    100          
    100          
544 6         32 push @PREINIT, "\t$_->{type}\t$_->{name};\n" for @opts;
545 6 100       20 push @CODE, 'switch(items' . ($class ? '-1' : q{}) . ") {\n";
546              
547 6         47 my $offset = scalar @args; # which is the first optional?
548 6         11 my $total = $offset + scalar @opts;
549 6         21 for my $i ($offset .. $total - 1) {
550 11         33 push @CODE, 'case ' . ($i + 1) . ":\n";
551 11         16 my @tmp;
552 11         23 for my $j ($offset .. $i) {
553 18         42 my $targ = $opts[$j - $offset]{name};
554 18         33 my $type = $opts[$j - $offset]{type};
555 18         37 my $src = "ST($j)";
556 18         44 my $conv = $o->typeconv($targ, $src, $type, 'input_expr');
557 18         50 push @CODE, $conv . ";\n";
558 18         44 push @tmp, $targ;
559             }
560 11 50       32 push @CODE, "\tRETVAL = " unless $void;
561             push @CODE,
562             call_or_instantiate($name, $ctor, $dtor, $class, $thing->{rconst},
563 11         46 $thing->{rtype}, (map { $_->{name} } @args), @tmp);
  6         17  
564 11         44 push @CODE, "\tbreak; /* case " . ($i + 1) . " */\n";
565             }
566 6         11 push @CODE, "default:\n";
567 6 50       17 push @CODE, "\tRETVAL = " unless $void;
568             push @CODE,
569             call_or_instantiate($name, $ctor, $dtor, $class, $thing->{rconst},
570 6         21 $thing->{rtype}, map { $_->{name} } @args);
  4         10  
571 6         21 push @CODE, "} /* switch(items) */ \n";
572             }
573             elsif ($void) {
574 7         17 push @CODE, "\t";
575             push @CODE,
576             call_or_instantiate($name, $ctor, $dtor, $class, 0, q{},
577 7         19 map { $_->{name} } @args);
  4         21  
578             }
579             elsif ($ellipsis or $thing->{rconst}) {
580 4         11 push @CODE, "\t";
581 4         9 push @CODE, 'RETVAL = ';
582             push @CODE,
583             call_or_instantiate($name, $ctor, $dtor, $class, $thing->{rconst},
584 4         23 $thing->{rtype}, map { $_->{name} } @args);
  0         0  
585             }
586 146 100       537 if ($void) {
    100          
587 7         16 push @CODE, <<'END';
588             if (PL_markstack_ptr != __temp_markstack_ptr) {
589             /* truly void, because dXSARGS not invoked */
590             PL_markstack_ptr = __temp_markstack_ptr;
591             XSRETURN_EMPTY; /* return empty stack */
592             }
593             /* must have used dXSARGS; list context implied */
594             return; /* assume stack size is correct */
595             END
596             }
597             elsif ($ellipsis) {
598 1         3 push @CODE, "\tPL_markstack_ptr = __temp_markstack_ptr;\n";
599             }
600              
601             # The actual function:
602 146         318 local $" = q{};
603 146 100       386 push @XS, "${t}PREINIT:\n@PREINIT" if @PREINIT;
604 146         298 push @XS, $t;
605 146 100 66     470 push @XS, 'PP' if $void and @CODE;
606 146 100       400 push @XS, "CODE:\n@CODE" if @CODE;
607 146 100 100     464 push @XS, "${t}OUTPUT:\nRETVAL\n" if @CODE and not $void;
608 146         285 push @XS, "\n";
609 146         849 return "@XS";
610             }
611              
612              
613             sub _map_subnames_cpp_to_perl {
614 146     146   366 my ($thing, $name, $class) = @_;
615 146         347 my ($XS, $ctor, $dtor) = (q{}, 0, 0);
616              
617 146 100       706 if ($name eq $class) { # ctor
    100          
    100          
618 47         174 $XS = $class . " *\n" . $class . '::new';
619 47         92 $ctor = 1;
620             }
621             elsif ($name eq "~$class") { # dtor
622 25         123 $XS = "void\n$class" . '::DESTROY';
623 25         71 $dtor = 1;
624             }
625             elsif ($class) { # method
626 58         278 $XS = "$thing->{rtype}\n$class" . "::$thing->{name}";
627             }
628             else { # function
629 16         68 $XS = "$thing->{rtype}\n$thing->{name}";
630             }
631 146         505 return ($XS, $ctor, $dtor);
632             }
633              
634              
635             sub call_or_instantiate {
636 42     42 0 11517 my ($name, $ctor, $dtor, $class, $const, $type, @args) = @_;
637              
638             # Create an rvalue (which might be const-casted later).
639 42         80 my $rval = q{};
640 42 100       107 $rval .= 'new ' if $ctor;
641 42 100       98 $rval .= 'delete ' if $dtor;
642 42 100 100     234 $rval .= 'THIS->' if ($class and not($ctor or $dtor));
      100        
643 42         126 $rval .= $name . '(' . join(q{,}, @args) . ')';
644              
645 42         99 return const_cast($rval, $const, $type) . ";\n";
646             } ### Tested.
647              
648             sub const_cast {
649 55     55 0 15949 my ($value, $const, $type) = @_;
650 55 100 100     382 return $value unless $const and $type =~ m/[*&]/x;
651 6         36 return "const_cast<$type>($value)";
652             } ### Tested.
653              
654             sub write_typemap {
655 44     44 0 141 my $o = shift;
656 44         341 my $filename = "$o->{API}{build_dir}/CPP.map";
657 44         214 my $type_kind = $o->{ILSM}{typeconv}{type_kind};
658 44         151 my $typemap = q{};
659             $typemap .= $_ . "\t" x 2 . $TYPEMAP_KIND . "\n"
660 44         133 for grep { $type_kind->{$_} eq $TYPEMAP_KIND } keys %{$type_kind};
  2293         4409  
  44         1061  
661 44 100       371 return unless length $typemap;
662              
663 38         465 my $tm_output = <<"END";
664             TYPEMAP
665             $typemap
666             OUTPUT
667             $TYPEMAP_KIND
668             $o->{ILSM}{typeconv}{output_expr}{$TYPEMAP_KIND}
669             INPUT
670             $TYPEMAP_KIND
671             $o->{ILSM}{typeconv}{input_expr}{$TYPEMAP_KIND}
672             END
673              
674              
675             # Open an output file, create if necessary, then lock, then truncate.
676             # This replaces the following, which wasn't lock-safe:
677              
678 38 50       3133 sysopen(my $TYPEMAP_FH, $filename, O_WRONLY | O_CREAT)
679             or croak "Error: Can't write to $filename: $!";
680              
681             # Flock and truncate (truncating to zero length to simulate '>' mode).
682 38 50       968 flock $TYPEMAP_FH, LOCK_EX
683             or croak "Error: Can't obtain lock for $filename: $!";
684 38 50       1803 truncate $TYPEMAP_FH, 0 or croak "Error: Can't truncate $filename: $!";
685              
686             # End of new lock-safe code.
687              
688 38         201 print {$TYPEMAP_FH} $tm_output;
  38         1439  
689              
690 38 50       349224 close $TYPEMAP_FH or croak "Error: Can't close $filename after write: $!";
691              
692 38         423 $o->validate(TYPEMAPS => $filename);
693 38         240 return;
694             }
695              
696             # Generate type conversion code: perl2c or c2perl.
697             sub typeconv {
698 124     124 0 489 my ($o, $var, $arg, $type, $dir, $preproc) = @_;
699 124         419 my $tkind = $o->{ILSM}{typeconv}{type_kind}{$type};
700 124         277 my $ret;
701             {
702 43     43   1158940 no strict; ## no critic (strict)
  43         115  
  43         1644  
  124         237  
703             # The conditional avoids uninitialized warnings if user passes
704             # a C++ function with 'void' as param.
705 124 50       445 if (defined $tkind) {
706              
707             # eval of typemap gives "Uninit"
708 43     43   244 no warnings 'uninitialized'; ## no critic (warnings)
  43         83  
  43         20923  
709             # Even without the conditional this line must remain.
710 124         10437 $ret = eval ## no critic (eval)
711             qq{qq{$o->{ILSM}{typeconv}{$dir}{$tkind}}};
712             }
713             else {
714 0         0 $ret = q{};
715             }
716             }
717 124         568 chomp $ret;
718 124 50       420 $ret =~ s/\n/\\\n/xg if $preproc;
719 124         618 return $ret;
720             }
721              
722             # Verify that the return type and all arguments can be bound to Perl.
723             sub check_type {
724 146     146 0 325 my ($o, $thing, $ctor, $dtor) = @_;
725 146         224 my $badtype;
726              
727             # strip "useless" modifiers so the type is found in typemap:
728 146         223 BADTYPE: while (1) {
729 146 100 100     720 if (!($ctor || $dtor)) {
730 74         200 my $t = $thing->{rtype};
731 74         416 $t =~ s/^(\s|const|virtual|static)+//xg;
732 74 50 66     626 if ($t ne 'void' && !$o->typeconv(q{}, q{}, $t, 'output_expr')) {
733 0         0 $badtype = $t;
734 0         0 last BADTYPE;
735             }
736             }
737 146         279 foreach (map { $_->{type} } @{$thing->{args}}) {
  40         180  
  146         492  
738 40         151 s/^(?:const|\s)+//xgo;
739 40 50 66     236 if ($_ ne '...' && !$o->typeconv(q{}, q{}, $_, 'input_expr')) {
740 0         0 $badtype = $_;
741 0         0 last BADTYPE;
742             }
743             }
744 146         472 return 1;
745             }
746              
747             # I don't really like this verbosity. This is what 'info' is for. Maybe we
748             # should ask Brian for an Inline=DEBUG option.
749             warn "No typemap for type $badtype. "
750             . "Skipping $thing->{rtype} $thing->{name}("
751 0           . join(', ', map { $_->{type} } @{$thing->{args}}) . ")\n"
752             if 0;
753 0           return 0;
754             }
755              
756             # Generate boot-code for enumeration constants:
757             sub make_enum {
758 0     0 0   my ($class, $name, $body) = @_;
759 0           my @enum;
760 0           push @enum, <<"END";
761             \t{
762             \t HV * pkg = gv_stashpv(\"$class\", 1);
763             \t if (pkg == NULL)
764             \t croak("Can't find package '$class'\\n");
765             END
766 0           my $val = 0;
767 0           foreach (@{$body}) {
  0            
768 0           my ($k, $v) = @{$_};
  0            
769 0 0         $val = $v if defined $v;
770 0           push @enum, "\tnewCONSTSUB(pkg, \"$k\", newSViv($val));\n";
771 0           ++$val;
772             }
773 0           push @enum, "\t}\n";
774 0           return join q{}, @enum;
775             }
776              
777              
778             1;
779              
780             __END__