File Coverage

blib/lib/Inline/CPP.pm
Criterion Covered Total %
statement 323 386 83.6
branch 125 174 71.8
condition 90 118 76.2
subroutine 37 39 94.8
pod 1 13 7.6
total 576 730 78.9


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