File Coverage

blib/lib/ExtUtils/XSBuilder/TypeMap.pm
Criterion Covered Total %
statement 21 396 5.3
branch 0 156 0.0
condition 0 88 0.0
subroutine 7 42 16.6
pod 0 34 0.0
total 28 716 3.9


line stmt bran cond sub pod time code
1             package ExtUtils::XSBuilder::TypeMap;
2              
3 1     1   4 use strict;
  1         2  
  1         35  
4 1     1   5 use warnings FATAL => 'all';
  1         1  
  1         37  
5              
6 1     1   573 use ExtUtils::XSBuilder::FunctionMap ();
  1         3  
  1         20  
7 1     1   538 use ExtUtils::XSBuilder::CallbackMap ();
  1         3  
  1         19  
8 1     1   541 use ExtUtils::XSBuilder::StructureMap ();
  1         3  
  1         28  
9 1     1   6 use ExtUtils::XSBuilder::MapUtil qw(list_first function_table structure_table callback_table callback_hash);
  1         2  
  1         60  
10 1     1   4 use Data::Dumper ;
  1         1  
  1         5774  
11              
12             our @ISA = qw(ExtUtils::XSBuilder::MapBase);
13              
14             sub new {
15 0     0 0   my $class = shift;
16 0           my $self = bless { INCLUDE => [], wrapxs => shift }, $class;
17              
18 0           $self->{function_map} = ExtUtils::XSBuilder::FunctionMap ->new ($self -> {wrapxs}),
19             $self->{structure_map} = ExtUtils::XSBuilder::StructureMap->new ($self -> {wrapxs}),
20             $self->{callback_map} = ExtUtils::XSBuilder::CallbackMap ->new ($self -> {wrapxs}),
21              
22             $self->get;
23 0           $self;
24             }
25              
26             my %special = map { $_, 1 } qw(UNDEFINED NOTIMPL CALLBACK);
27              
28             sub special {
29 0     0 0   my($self, $class) = @_;
30 0           return $special{$class};
31             }
32              
33 0     0 0   sub function_map { shift->{function_map}->get }
34 0     0 0   sub structure_map { shift->{structure_map}->get }
35 0     0 0   sub callback_map { shift->{callback_map}->get }
36              
37             sub parse {
38 0     0 0   my($self, $fh, $map) = @_;
39              
40 0           while ($fh->readline) {
41 0 0         if (/E=/) {
42 0           my %args = $self->parse_keywords($_);
43 0           while (my($key,$val) = each %args) {
44 0           push @{ $self->{$key} }, $val;
  0            
45             }
46 0           next;
47             }
48              
49 0           my @aliases;
50 0           my($type, $class, $typemapid, $aliastypes, $malloctype) = split /\s*\|\s*/, $_, 5;
51 0 0 0       if (!$typemapid && $class)
52             {
53 0 0         if ($class =~ /::/) {
54 0           $typemapid = 'T_PTROBJ';
55             }
56             else {
57 0           $typemapid = "T_$class";
58             }
59             }
60 0   0       $class ||= 'UNDEFINED';
61              
62 0 0         if ($type =~ s/^struct\s+(.*)/$1/) {
    0          
63 0           push @aliases,
64             "$type *", "const $type *",
65             $type, "const $type",
66             "struct $type", "const struct $type",
67             "struct $type *", "const struct $type *",
68             "$type **", "const $type **" ;
69              
70 0           my $cname = $class;
71 0 0         if ($cname =~ s/::/__/g) {
72 0           push @{ $self->{typedefs} }, [$type, $cname];
  0            
73             }
74             }
75             elsif ($type =~ /_t$/) {
76 0           push @aliases, $type, "$type *", "const $type *";
77             }
78             else {
79 0           push @aliases, $type;
80             }
81              
82 0           my $t = { class => $class,
83             typemapid => $typemapid } ;
84 0 0         $t -> {aliastypes} = [ split (/\s*,\s*/, $aliastypes) ] if ($aliastypes) ;
85 0 0         $t -> {malloctype} = $malloctype if ($malloctype) ;
86              
87 0           for (@aliases) {
88 0           $map->{$_} = $t ;
89             }
90             }
91             }
92              
93             sub get {
94 0     0 0   my $self = shift;
95              
96 0   0       $self->{map} ||= $self->parse_map_files;
97             }
98              
99             my $ignore = join '|', qw{
100             ap_LINK ap_HOOK _ UINT union._
101             union.block_hdr cleanup process_chain
102             iovec struct.rlimit Sigfunc in_addr_t
103             };
104              
105             sub should_ignore {
106 0     0 0   my($self, $type) = @_;
107 0 0         return 1 if $type =~ /^($ignore)/o;
108             }
109              
110             sub is_callback {
111 0     0 0   my($self, $type) = @_;
112 0 0 0       return 1 if $type =~ /\(/ and $type =~ /\)/; #XXX: callback
113             }
114              
115             sub exists {
116 0     0 0   my($self, $type) = @_;
117              
118 0 0 0       return 1 if $self->is_callback($type) || $self->should_ignore($type);
119              
120 0           $type =~ s/\[\d+\]$//; #char foo[64]
121              
122 0           return exists $self->get->{$type};
123             }
124              
125             sub map_type {
126 0     0 0   my($self, $type, $quiet) = @_;
127 0           my $t = $self->get->{$type};
128 0           my $class = $t -> {class} ;
129              
130 0 0 0       unless ($class and ! $self->special($class))
131             {
132 0 0         print "WARNING: Type '$type' not in mapfile\n" if (!$quiet);
133 0           return undef ;
134             }
135 0 0         if ($class =~ /(.*?)::$/) {
136 0           return $1 ;
137             }
138 0 0         if ($class =~ /::/) {
139 0           return $class;
140             }
141             else {
142 0           return $type;
143             }
144             }
145              
146             sub map_malloc_type {
147 0     0 0   my($self, $type) = @_;
148 0           my $t = $self->get->{$type};
149 0           return $t -> {malloctype} ;
150             }
151              
152             sub map_class {
153 0     0 0   my($self, $type) = @_;
154 0           my $t = $self->get->{$type};
155 0           my $class = $t -> {class} ;
156              
157 0 0 0       return unless $class and ! $self->special($class);
158 0 0         if ($class =~ /(.*?)::$/) {
159 0           return $1 ;
160             }
161 0           return $class ;
162             }
163              
164             sub null_type {
165 0     0 0   my($self, $type) = @_;
166 0           my $t = $self->get->{$type};
167 0           my $class = $t -> {class} ;
168              
169 0 0         if ($class =~ /^[INU]V/) {
    0          
170 0           return '0';
171             }
172             elsif ($class =~ /^(U_)?CHAR$/) {
173 0           return '0'; # xsubpp seems to mangle q{'\0'}
174             }
175             else {
176 0           return 'NULL';
177             }
178             }
179              
180             sub can_map {
181 0     0 0   my $self = shift;
182 0           my $map = shift;
183 0           my $return_type = shift ;
184              
185 0 0         if (!$self->map_type($return_type))
186             {
187 0   0       print "WARNING: Cannot map return type $return_type for function ", $map->{name} || '???', "\n" ;
188 0           return undef ;
189             }
190              
191 0 0         return 1 if ($map->{argspec}) ;
192              
193 0           for (@_) {
194 0 0         if (!$self->map_type($_))
195             {
196 0   0       print "WARNING: Cannot map type $_ for function ", $map->{name} || '???', "\n" ;
197 0           return undef ;
198             }
199             }
200              
201 0           return 1;
202             }
203              
204             sub map_arg {
205 0     0 0   my($self, $arg) = @_;
206             #print Dumper ($arg), 'map ', $self->map_type($arg->{type}), "\n" ;
207             return {
208 0   0       name => $arg->{name},
      0        
209             default => $arg->{default},
210             type => $self->map_type($arg->{type}) || $arg->{type},
211             rtype => $arg->{type},
212             class => $self->{map}->{$arg->{type}}->{class} || "",
213             }
214             }
215              
216             sub map_args {
217 0     0 0   my($self, $func, $entry) = @_;
218              
219             #my $entry = $self->function_map->{ $func->{name} };
220 0           my $argspec = $entry->{argspec};
221 0           my $args = [];
222 0           my $retargs = [];
223              
224 0 0         if ($argspec) {
225 0           $entry->{orig_args} = [ map $_->{name}, @{ $func->{args} } ];
  0            
226              
227             #print "argspec ", Dumper($argspec) ;
228 0           for my $arg (@$argspec) {
229 0           my $default;
230             my $return ;
231 0 0         if ($arg =~ /^<(.*?)$/) {
232 0           $arg = $1 ;
233 0           $return = 1 ;
234             }
235            
236 0           ($arg, $default) = split /=/, $arg, 2;
237 0           my($type, $name) ;
238 0 0         if ($arg =~ /^(.+)\s*:\s*(.+)$/)
239             {
240 0           $type = $1 ;
241 0           $name = $2 ;
242             }
243              
244             #my($type, $name) = split /:(?:[^:])/, $arg, 2;
245              
246 0           my $arghash ;
247 0 0 0       if ($type and $name) {
248 0           $arghash = {
249             name => $name,
250             type => $type,
251             default => $default,
252             };
253             }
254             else {
255 0     0     my $e = list_first { $_->{name} eq $arg } @{ $func->{args} };
  0            
  0            
256 0 0         if ($e) {
    0          
257 0           $arghash = { %$e, default => $default};
258             }
259             elsif ($arg eq '...') {
260 0           $arghash = { name => '...', type => 'SV *'};
261             }
262             else {
263 0           warn "bad argspec: $func->{name} ($arg)\n", Dumper ($func->{args}) ;
264             }
265             }
266 0 0         if ($arghash){
267 0 0         if ($return) {
268 0           $arghash -> {return} = 1 ;
269 0           $arghash -> {type} =~ s/\s*\*$// ;
270 0           push @$retargs, $arghash ;
271             }
272             else {
273 0           push @$args, $arghash ;
274             }
275             }
276             }
277             }
278             else {
279 0           $args = $func->{args};
280             }
281              
282 0           return ([ map $self->map_arg($_), @$args ], [ map $self->map_arg($_), @$retargs ]) ;
283             }
284              
285             # ============================================================================
286              
287             sub map_cb_or_func {
288 0     0 0   my($self, $func, $map, $class) = @_;
289              
290 0 0         return unless $map;
291              
292 0           return unless $self->can_map($map, $func->{return_type} || 'void',
293 0 0 0       map $_->{type}, @{ $func->{args} });
294 0           my ($mfargs, $mfretargs) = $self->map_args($func, $map) ;
295              
296 0   0       my $mf = {
297             name => $func->{name},
298             comment => $func->{comment},
299             return_type => $self->map_type($map->{return_type} ||
300             $func->{return_type} || 'void'),
301             args => $mfargs,
302             retargs => $mfretargs,
303             perl_name => $map->{name},
304             };
305              
306 0           for (qw(dispatch argspec dispatch_argspec orig_args prefix)) {
307 0           $mf->{$_} = $map->{$_};
308             }
309              
310 0 0         $mf->{class} = $class if ($class) ;
311              
312 0 0         unless ($mf->{class}) {
313 0   0       $mf->{class} = $map->{class} || $self->first_class($mf);
314             #print "GUESS class=$mf->{class} for $mf->{name}\n";
315             }
316              
317 0   0       $mf->{prefix} ||= $self -> {function_map} -> guess_prefix($mf);
318              
319 0   0       $mf->{module} = $map->{module} || $mf->{class};
320              
321 0           $mf;
322             }
323              
324             # ============================================================================
325              
326             sub map_function {
327 0     0 0   my($self, $func) = @_;
328              
329 0           my $map = $self->function_map->{ $func->{name} };
330 0 0         return unless $map;
331              
332 0           return $self -> map_cb_or_func ($func, $map) ;
333             }
334              
335             # ============================================================================
336              
337             sub map_callback {
338 0     0 0   my($self, $callb, $class) = @_;
339              
340 0           my $name = $callb -> {type} ;
341 0           my $callback = callback_hash ($self -> {wrapxs}) -> {$name} ;
342             #print $callb -> {name} || '???' ," $name -> ", $callback || '-', "\n" ;
343 0 0         return unless $callback;
344              
345 0           my $map = $self->callback_map->{ $name };
346             #print "$name -> map=", $map || '-', "\n" ;
347 0 0         return unless $map;
348              
349 0           my $cb = $self -> map_cb_or_func ($callback, $map, $class) ;
350              
351 0 0         return unless $cb ;
352              
353 0           my $orig_args = $cb -> {orig_args} ;
354 0 0         $orig_args = [ map $_->{name}, @{ $cb->{args} } ] if (!$orig_args) ;
  0            
355            
356 0           my %args = map { $_->{name} => $_ } @{ $cb->{args} } ;
  0            
  0            
357 0           my %retargs = map { $_->{name} => $_ } @{ $cb->{retargs} } ;
  0            
  0            
358              
359             #print "mcb ", Dumper($cb), " cba ", Dumper($callback->{args}) , " args ", Dumper(\%args) ;
360              
361 0           $cb -> {orig_args} = [ map ($retargs{$_}?"\&$_":(($args{$_}{type} !~ /::/) || ($args{$_}{rtype} =~ /\*$/)?
362 0 0 0       $_:"*$_"), @{ $orig_args }) ];
    0          
363              
364 0           my $cbargs = [ { type => $class, name => '__self'} ] ;
365 0 0         push @$cbargs, @{ $cb->{args} } if (@{ $cb->{args}}) ;
  0            
  0            
366 0           $cb->{args} = $cbargs ;
367              
368             #print 'func', Dumper($callback), 'map', Dumper($map), 'cb', Dumper($cb) ;
369              
370 0           return $cb ;
371             }
372              
373             # ============================================================================
374              
375             sub map_structure {
376 0     0 0   my($self, $struct) = @_;
377              
378 0           my($class, @elts);
379 0           my $stype = $struct->{type};
380              
381 0 0         return unless ($class = $self->map_type($stype)) ;
382              
383 0   0       my $module = $self->{structure_map}->{MODULES}->{$stype} || $class ;
384 0           for my $e (@{ $struct->{elts} }) {
  0            
385 0           my($name, $type) = ($e->{name}, $e->{type});
386 0           my $rtype;
387             my $mapping ;
388              
389 0 0         if (!exists ($self->structure_map->{$stype}->{$name}))
390             {
391 0 0         if (!$name)
392             {
393 0           print "WARNING: The following struct element is not in mapfile and has no name\n", Dumper ($e) ;
394             }
395             else
396             {
397 0           print "WARNING: $name not in mapfile\n" ;
398             }
399 0           next ;
400             }
401 0 0         if (!($mapping = $self->structure_map->{$stype}->{$name}))
402             {
403 0           print "WARNING: $stype for $name not in mapfile\n" ;
404 0           next ;
405             }
406 0           my $mallocmap = $self->structure_map->{$stype}{-malloc} ;
407 0           my $freemap = $self->structure_map->{$stype}{-free} ;
408              
409             #print 'mapping: ', Dumper($mapping, $type) ;
410              
411 0 0         if ($rtype = $self->map_type($type, 1)) {
    0          
412             #print "rtype=$rtype\n" ;
413 0           my $malloctype = $self->map_malloc_type($type) ;
414 0 0 0       push @elts, {
    0 0        
      0        
415             name => $name,
416             perl_name => $mapping -> {perl_name} || $name,
417             comment => $e -> {comment},
418             type => $mapping -> {type} || $rtype,
419             rtype => $type,
420             default => $self->null_type($type),
421             pool => $self->class_pool($class),
422             class => $self->{map}->{$type}{class} || "",
423             $malloctype?(malloc => $mallocmap -> {$malloctype}):(),
424             $malloctype?(free => $freemap -> {$malloctype}):(),
425             };
426            
427             #print Dumper($elts[-1], $stype, $mallocmap, $self->map_malloc_type($type)) ;
428             }
429             elsif ($rtype = $self->map_callback($e, $class)) {
430 0   0       push @elts, {
      0        
      0        
431             name => $name,
432             perl_name => $mapping -> {perl_name} || $name,
433             func => { %$rtype, name => $name, perl_name => $rtype->{alias} || $name, module => $module, dispatch => "(*__self->$name)", comment => $e -> {comment}},
434             rtype => $type,
435             default => 'NULL',
436             #pool => $self->class_pool($class),
437             class => $class || "",
438             callback => 1,
439             };
440             }
441             else
442             {
443 0           print "WARNING: Type '$type' for struct memeber '$name' in not in types mapfile\n" ;
444             }
445              
446             }
447              
448             return {
449 0 0         module => $module,
    0          
450             class => $class,
451             type => $stype,
452             elts => \@elts,
453             has_new => $self->structure_map->{$stype}->{'new'}?1:0,
454             has_private => $self->structure_map->{$stype}->{'private'}?1:0,
455             comment => $struct -> {comment},
456              
457             };
458             }
459              
460             sub destructor {
461 0     0 0   my($self, $prefix) = @_;
462 0           $self->function_map->{$prefix . 'DESTROY'};
463             }
464              
465              
466 0     0 0   sub first_class_ok { 1 } ;
467              
468             sub first_class {
469 0     0 0   my($self, $func) = @_;
470 0           my $map = $self->get ;
471              
472 0           for my $e (@{ $func->{args} }) {
  0            
473             ###next unless $e->{type} =~ /::/;
474             # use map -> rtype to catch class::
475 0 0         next unless $map->{$e->{rtype}}{class} =~ /::/;
476            
477             #there are alot of util functions that take an APR::Pool
478             #that do not belong in the APR::Pool class
479             ###next if (!$self -> first_class_ok ($func, $e)) ;
480 0 0 0       next if $e->{type} eq 'APR::Pool' and $func->{name} !~ /^apr_pool/;
481 0 0         return $1 if ($e->{type} =~ /^(.*?)::$/) ;
482 0           return $e->{type};
483             }
484              
485 0 0         return $func->{name} =~ /^apr_/ ? 'APR' : 'Apache';
486             }
487              
488             sub check {
489 0     0 0   my $self = shift;
490              
491 0           my(@types, @missing, %seen);
492              
493 0           for my $entry (@{ structure_table($self -> {wrapxs}) }) {
  0            
494 0           push @types, map $_->{type}, @{ $entry->{elts} } ;
  0            
495 0   0       my $type = $entry -> {stype} || $entry->{type} ;
496 0 0         push @types, $type =~/^struct\s+/?$type:"struct $type" ;
497             }
498              
499 0           for my $entry (@{ function_table($self -> {wrapxs}) }) {
  0            
500 0           push @types, grep { not $seen{$_}++ }
  0            
501             ($entry->{return_type},
502 0           map $_->{type}, @{ $entry->{args} })
503             }
504              
505             #printf "%d types\n", scalar @types;
506              
507 0           for my $type (@types) {
508 0           $type =~ s/\s*(\*\s*)+$// ;
509 0           $type =~ s/const\s*// ;
510             #$type =~ s/struct\s*// ;
511 0 0 0       push @missing, $type unless ($self->exists($type) || $type eq 'new' || $type eq 'private') ;
      0        
512             }
513              
514 0 0         return @missing ? \@missing : undef;
515             }
516              
517             #look for Apache/APR structures that do not exist in structure.map
518             my %ignore_check = map { $_,1 } qw{
519             module_struct cmd_how kill_conditions
520             regex_t regmatch_t pthread_mutex_t
521             unsigned void va_list ... iovec char int long const
522             gid_t uid_t time_t pid_t size_t
523             sockaddr hostent
524             SV
525             };
526              
527             sub check_exists {
528 0     0 0   my $self = shift;
529              
530 0           my %structures = map { my $t = $_->{type}; $t =~ s/^struct\s+// ; ($_->{type} => 1, $t => 1) } @{ structure_table($self) };
  0            
  0            
  0            
  0            
531 0           my @missing = ();
532 0           my %seen;
533             #print Data::Dumper -> Dump ([\%structures, structure_table($self)]) ;
534              
535 0           for my $name (keys %{ $self->{map} }) {
  0            
536 0           1 while $name =~ s/^\w+\s+(\w+)/$1/;
537 0           $name =~ s/\s+\**.*$//;
538 0 0 0       next if $seen{$name}++ or $structures{$name} or $ignore_check{$name};
      0        
539 0           push @missing, $name;
540             }
541              
542 0 0         return @missing ? \@missing : undef;
543             }
544              
545              
546             sub checkmaps {
547              
548 0     0 0   my $self = shift ;
549 0           my %result ;
550 0           $result{missing_functions} = $self->{function_map} -> check ;
551 0           $result{obsolete_functions} = $self->{function_map} -> check_exists ;
552 0           $result{missing_callbacks} = $self->{callback_map} -> check ;
553 0           $result{obsolete_callbacks} = $self->{callback_map} -> check_exists ;
554 0           $result{missing_structures} = $self->{structure_map} -> check ;
555 0           $result{obsolete_structures} = $self->{structure_map} -> check_exists ;
556 0           $result{missing_types} = $self-> check ;
557 0           $result{obsolete_types} = $self-> check_exists ;
558              
559 0           return \%result ;
560             }
561              
562             sub writemaps {
563              
564 0     0 0   my $self = shift ;
565 0           my $result = shift ;
566 0           my $prefix = shift ;
567 0           $self->{function_map} -> write_map_file ($result -> {missing_functions}, $prefix) ;
568 0           $self->{callback_map} -> write_map_file ($result -> {missing_callbacks}, $prefix) ;
569 0           $self->{structure_map} -> write_map_file ($result -> {missing_structures}, $prefix) ;
570 0           $self -> write_map_file ($result -> {missing_types}) ;
571             }
572              
573              
574             sub write {
575 0     0 0   my ($self, $fh, $newentries) = @_ ;
576              
577 0           my %types ;
578 0           foreach my $type (@$newentries)
579             {
580 0           $type =~ s/\s*(\*\s*)+$// ;
581 0           $type =~ s/const\s*// ;
582             #$type =~ s/struct\s*// ;
583 0           $types{$type} = 1 ;
584             }
585            
586 0           foreach my $type (sort keys %types)
587             {
588 0           $fh -> print ("$type\t|\n") ;
589             }
590             }
591              
592              
593             #XXX: generate this
594             my %class_pools = map {
595             (my $f = "mpxs_${_}_pool") =~ s/:/_/g;
596             $_, $f;
597             } qw{
598             Apache::RequestRec Apache::Connection Apache::URI
599             };
600              
601             sub class_pool : lvalue {
602 0     0 0   my($self, $class) = @_;
603 0           $class_pools{$class};
604             }
605              
606              
607             sub h_wrap {
608 0     0 0   my($self, $file, $code) = @_;
609              
610 0           $file = $self -> {wrapxs} -> h_filename_prefix . $file;
611              
612 0           my $h_def = uc "${file}_h";
613 0           my $preamble = "\#ifndef $h_def\n\#define $h_def\n\n";
614 0           my $postamble = "\n\#endif /* $h_def */\n";
615              
616 0           return ("$file.h", $preamble . $code . $postamble);
617             }
618              
619             sub typedefs_code {
620 0     0 0   my $self = shift;
621 0           my $map = $self->get;
622 0           my %seen;
623              
624 0           my $file = $self -> {wrapxs} -> h_filename_prefix . 'typedefs';
625 0           my $h_def = uc "${file}_h";
626 0           my $code = "";
627 0           my @includes ;
628              
629 0           for (@includes, @{ $self->{INCLUDE} }) {
  0            
630 0           $code .= qq{\#include "$_"\n}
631             }
632              
633 0           for my $t (@{ $self->{typedefs} }) {
  0            
634 0 0         next if $seen{ $t->[1] }++;
635 0           my $class = $t->[1] ;
636 0           $class =~ s/__$// ;
637 0           $code .= "typedef $t->[0] * $class;\n";
638             }
639              
640 0           $code .= "typedef void * PTR;\n";
641 0           $code .= "#if PERL_VERSION > 5\n";
642 0           $code .= "typedef char * PV;\n";
643 0           $code .= "#endif\n";
644 0           $code .= "typedef char * PVnull;\n";
645              
646 0           $code .= q{
647             #ifndef pTHX_
648             #define pTHX_
649             #endif
650             #ifndef aTHX_
651             #define aTHX_
652             #endif
653             #ifndef pTHX
654             #define pTHX
655             #endif
656             #ifndef aTHX
657             #define aTHX
658             #endif
659              
660             #ifndef XSprePUSH
661             #define XSprePUSH (sp = PL_stack_base + ax - 1)
662             #endif
663              
664             } ;
665              
666 0           $self->h_wrap('typedefs', $code);
667             }
668              
669             sub sv_convert_code {
670 0     0 0   my $self = shift;
671 0           my $map = $self->get;
672 0           my %seen;
673 0           my $cnvprefix = $self -> {wrapxs} -> my_cnv_prefix ;
674 0           my $typemap_code = $self -> typemap_code ($cnvprefix);
675 0           my $code = q{
676            
677             #ifndef aTHX_
678             /* let it work with 5.005 */
679             #define aTHX_
680             #endif
681             } ;
682              
683 0           while (my($ctype, $t) = each %$map) {
684 0           my $ptype = $t -> {class} ;
685 0 0         next if $self->special($ptype);
686 0 0         next if ($ctype =~ /\s/) ;
687 0           my $class = $ptype;
688 0           my $tmcode ;
689              
690 0           $ptype =~ s/:/_/g ;
691 0           $ptype =~ s/__$// ;
692 0           $class =~ s/::$// ;
693 0 0         next if $seen{$ptype}++;
694              
695 0 0         if ($typemap_code -> {$t -> {typemapid}}) {
696 0           my $alias;
697 0           my $expect = "expecting an $class derived object";
698 0           my $croak = "argument is not a blessed reference";
699              
700             #Perl -> C
701 0           my $define = "${cnvprefix}sv2_$ptype";
702              
703 0 0         if ($tmcode = $typemap_code -> {$t -> {typemapid}}{perl2c})
704             {
705 0           $code .= "#define $define(sv) " . eval (qq[qq[$tmcode]]) . "\n" ;
706             }
707             else
708             {
709 0           print "WARNING no convert code for $t -> {typemapid}\n" ;
710             }
711 0 0         if ($alias = $t -> {typealiases}[0]) {
712 0           $code .= "#define ${cnvprefix}sv2_$alias $define\n\n";
713             }
714              
715             #C -> Perl
716 0           $define = "${cnvprefix}${ptype}_2obj";
717 0 0         if ($tmcode = $typemap_code -> {$t -> {typemapid}}{c2perl})
718             {
719 0           $code .= "#define $define(ptr) " . eval (qq[qq[$tmcode]]) . "\n" ;
720             }
721             else
722             {
723 0           print "WARNING no convert code for $t -> {typemapid}\n" ;
724             }
725 0 0         if ($alias) {
726 0           $code .= "#define ${cnvprefix}${alias}_2obj $define\n\n";
727             }
728              
729             #Create
730 0           $define = "${cnvprefix}${ptype}_create_obj";
731 0 0         if ($tmcode = $typemap_code -> {$t -> {typemapid}}{create})
732             {
733 0           $code .= "#define $define(p,sv,rv,alloc) " . eval (qq[qq[$tmcode]]) . "\n" ;
734             }
735              
736 0 0         if ($alias) {
737 0           $code .= "#define ${cnvprefix}${alias}_2obj $define\n\n";
738             }
739             #Destroy
740 0           $define = "${cnvprefix}${ptype}_free_obj";
741 0 0         if ($tmcode = $typemap_code -> {$t -> {typemapid}}{destroy})
742             {
743 0           $code .= "#define $define(ptr) " . eval (qq[qq[$tmcode]]) . "\n" ;
744             }
745              
746 0 0         if ($alias) {
747 0           $code .= "#define ${cnvprefix}${alias}_2obj $define\n\n";
748             }
749             }
750             else {
751 0 0 0       if (($ptype =~ /^(\wV)$/) && $ptype ne 'SV') {
752 0           my $class = $1;
753 0           my $alias ;
754              
755             #Perl -> C
756 0           my $define = "${cnvprefix}sv2_$ctype";
757              
758 0           $code .= "#define $define(sv) ($ctype)Sv$class(sv)\n\n";
759              
760 0 0         if ($alias = $t -> {typealiases}[0]) {
761 0           $code .= "#define ${cnvprefix}sv2_$alias $define\n\n";
762             }
763             #C -> Perl
764 0           $define = "${cnvprefix}${ctype}_2obj";
765 0           my $lcclass = lc($class) ;
766 0 0         my $l = $class eq 'PV'?',0':'' ;
767              
768 0           $code .= "#define $define(v) sv_2mortal(newSV$lcclass(v$l))\n\n";
769              
770 0 0         if ($alias) {
771 0           $code .= "#define ${cnvprefix}${alias}_2obj $define\n\n";
772             }
773             }
774             }
775             }
776              
777 0           $code .= "#define ${cnvprefix}sv2_SV(sv) (sv)\n\n";
778 0           $code .= "#define ${cnvprefix}SV_2obj(x) (x)\n\n";
779 0           $code .= "#define ${cnvprefix}sv2_SVPTR(sv) (sv)\n\n";
780 0           $code .= "#define ${cnvprefix}SVPTR_2obj(x) (x==NULL?&PL_sv_undef:sv_2mortal(SvREFCNT_inc(x)))\n\n";
781 0           $code .= "#define ${cnvprefix}sv2_PV(sv) (SvPV(sv, PL_na))\n\n";
782 0           $code .= "#define ${cnvprefix}PV_2obj(x) (sv_2mortal(newSVpv(x, 0)))\n\n";
783 0           $code .= "#define ${cnvprefix}sv2_PVnull(sv) (SvOK(sv)?SvPV(sv, PL_na):NULL)\n\n";
784 0           $code .= "#define ${cnvprefix}PVnull_2obj(x) (x==NULL?&PL_sv_undef:sv_2mortal(newSVpv(x, 0)))\n\n";
785 0           $code .= "#define ${cnvprefix}sv2_IV(sv) SvIV(sv)\n\n";
786 0           $code .= "#define ${cnvprefix}IV_2obj(x) sv_2mortal(newSViv(x))\n\n";
787 0           $code .= "#define ${cnvprefix}sv2_NV(sv) SvNV(sv)\n\n";
788 0           $code .= "#define ${cnvprefix}NV_2obj(x) sv_2mortal(newSVnv(x))\n\n";
789 0           $code .= "#define ${cnvprefix}sv2_UV(sv) SvUV(sv)\n\n";
790 0           $code .= "#define ${cnvprefix}UV_2obj(x) sv_2mortal(newSVuv(x))\n\n";
791 0           $code .= "#define ${cnvprefix}sv2_PTR(sv) (SvROK(sv)?((void *)SvIV(SvRV(sv))):NULL)\n\n";
792 0           $code .= "#define ${cnvprefix}PTR_2obj(x) (x?newRV_noinc(newSViv ((IV)x)):&PL_sv_undef)\n\n";
793 0           $code .= "#define ${cnvprefix}sv2_CHAR(sv) (char)SvNV(sv)\n\n";
794 0           $code .= "#define ${cnvprefix}CHAR_2obj(x) sv_2mortal(newSVnv(x))\n\n";
795 0           $code .= "#define ${cnvprefix}sv2_AVREF(sv) (AV*)SvRV(sv)\n\n";
796 0           $code .= "#define ${cnvprefix}AVREF_2obj(x) (x?sv_2mortal(newRV((SV*)x)):&PL_sv_undef)\n\n";
797 0           $code .= "#define ${cnvprefix}sv2_HVREF(sv) (HV*)SvRV(sv)\n\n";
798 0           $code .= "#define ${cnvprefix}HVREF_2obj(x) (x?sv_2mortal(newRV((SV*)x)):&PL_sv_undef)\n\n";
799              
800 0           $self->h_wrap('sv_convert', $code);
801             }
802              
803             # ============================================================================
804              
805             # NOTE: 'INPUT' code must not be ended with a ;
806              
807              
808             sub typemap_code
809              
810             {
811 0     0 0   my $self = shift ;
812 0           my $cnvprefix = shift ;
813              
814             return
815             {
816 0           'T_MAGICHASH_SV' =>
817             {
818             'OUTPUT' => ' if ($var -> _perlsv) $arg = $var -> _perlsv ; else $arg = &sv_undef ;',
819              
820             'c2perl' => '(ptr->_perlsv?ptr->_perlsv:&sv_undef)',
821              
822             'INPUT' =>
823             q[ {
824             MAGIC * mg ;
825             if ((mg = mg_find (SvRV($arg), '~')))
826             $var = *(($type *)(mg -> mg_ptr)) ;
827             else
828             croak (\"$var is not of type $type\") ;
829             }
830             ],
831              
832             'perl2c' =>
833             q[(SvOK(sv)?((SvROK(sv) && SvMAGICAL(SvRV(sv))) \\\\
834             || (Perl_croak(aTHX_ "$croak ($expect)"),0) ? \\\\
835             *(($ctype **)(mg_find (SvRV(sv), '~') -> mg_ptr)) : ($ctype *)NULL):($ctype *)NULL)
836             ],
837              
838             'create' =>
839             q[ sv = (SV *)newHV () ; \\\\
840             p = alloc ; \\\\
841             memset (p, 0, sizeof($ctype)) ; \\\\
842             sv_magic ((SV *)sv, NULL, '~', (char *)&p, sizeof (p)) ; \\\\
843             rv = p -> _perlsv = newRV_noinc ((SV *)sv) ; \\\\
844             sv_bless (rv, gv_stashpv ("$class", 0)) ;
845            
846             ],
847             'destroy' => ' free(ptr)',
848             },
849              
850             'T_PTROBJ' =>
851             {
852             'c2perl' => ' sv_setref_pv(sv_newmortal(), "$class", (void*)ptr)',
853              
854             'perl2c' =>
855             q[(SvOK(sv)?((SvROK(sv) && (SvTYPE(SvRV(sv)) == SVt_PVMG)) \\\\
856             || (Perl_croak(aTHX_ "$croak ($expect)"),0) ? \\\\
857             ($ctype *)SvIV((SV*)SvRV(sv)) : ($ctype *)NULL):($ctype *)NULL)
858             ],
859              
860             'create' =>
861             q[ rv = newSViv(0) ; \\\\
862             sv = newSVrv (rv, "$class") ; \\\\
863             SvUPGRADE(sv, SVt_PVIV) ; \\\\
864             SvGROW(sv, sizeof (*p)) ; \\\\
865             p = ($ctype *)SvPVX(sv) ;\\\\
866             memset(p, 0, sizeof (*p)) ;\\\\
867             SvIVX(sv) = (IV)p ;\\\\
868             SvIOK_on(sv) ;\\\\
869             SvPOK_on(sv) ;
870             ],
871              
872             },
873             'T_AVREF' =>
874             {
875             'OUTPUT' => " \$arg = SvREFCNT_inc (${cnvprefix}AVREF_2obj(\$var));",
876             'INPUT' => " \$var = ${cnvprefix}sv2_AVREF(\$arg)",
877             },
878             'T_HVREF' =>
879             {
880             'OUTPUT' => " \$arg = SvREFCNT_inc (${cnvprefix}HVREF_2obj(\$var));",
881             'INPUT' => " \$var = ${cnvprefix}sv2_HVREF(\$arg)",
882             },
883             'T_SVPTR' =>
884             {
885             'OUTPUT' => " \$arg = SvREFCNT_inc (${cnvprefix}SVPTR_2obj(\$var));",
886             'INPUT' => " \$var = (\$type)${cnvprefix}sv2_SVPTR(\$arg)",
887             },
888             'T_PVnull' =>
889             {
890             'OUTPUT' => " \$arg = SvREFCNT_inc (${cnvprefix}PVnull_2obj(\$var));",
891             'INPUT' => " \$var = (\$type)${cnvprefix}sv2_PVnull(\$arg)",
892             },
893              
894             },
895             }
896              
897              
898              
899              
900             1;
901             __END__