File Coverage

blib/lib/ExtUtils/Typemaps.pm
Criterion Covered Total %
statement 342 364 93.9
branch 128 174 73.5
condition 40 59 67.8
subroutine 31 33 93.9
pod 20 21 95.2
total 561 651 86.1


line stmt bran cond sub pod time code
1             package ExtUtils::Typemaps;
2 24     24   1133628 use 5.006001;
  24         103  
3 24     24   176 use strict;
  24         79  
  24         869  
4 24     24   128 use warnings;
  24         64  
  24         108525  
5             our $VERSION = '3.63';
6              
7             require ExtUtils::ParseXS;
8             require ExtUtils::ParseXS::Constants;
9             require ExtUtils::Typemaps::InputMap;
10             require ExtUtils::Typemaps::OutputMap;
11             require ExtUtils::Typemaps::Type;
12              
13             =head1 NAME
14              
15             ExtUtils::Typemaps - Read/Write/Modify Perl/XS typemap files
16              
17             =head1 SYNOPSIS
18              
19             # read/create file
20             my $typemap = ExtUtils::Typemaps->new(file => 'typemap');
21             # alternatively create an in-memory typemap
22             # $typemap = ExtUtils::Typemaps->new();
23             # alternatively create an in-memory typemap by parsing a string
24             # $typemap = ExtUtils::Typemaps->new(string => $sometypemap);
25              
26             # add a mapping
27             $typemap->add_typemap(ctype => 'NV', xstype => 'T_NV');
28             $typemap->add_inputmap(
29             xstype => 'T_NV', code => '$var = ($type)SvNV($arg);'
30             );
31             $typemap->add_outputmap(
32             xstype => 'T_NV', code => 'sv_setnv($arg, (NV)$var);'
33             );
34             $typemap->add_string(string => $typemapstring);
35             # will be parsed and merged
36              
37             # remove a mapping (same for remove_typemap and remove_outputmap...)
38             $typemap->remove_inputmap(xstype => 'SomeType');
39              
40             # save a typemap to a file
41             $typemap->write(file => 'anotherfile.map');
42              
43             # merge the other typemap into this one
44             $typemap->merge(typemap => $another_typemap);
45              
46             =head1 DESCRIPTION
47              
48             This module can read, modify, create and write Perl XS typemap files. If you don't know
49             what a typemap is, please confer the L and L manuals.
50              
51             The module is not entirely round-trip safe: For example it currently simply strips all comments.
52             The order of entries in the maps is, however, preserved.
53              
54             We check for duplicate entries in the typemap, but do not check for missing
55             C entries for C or C entries since these might be hidden
56             in a different typemap.
57              
58             =head1 METHODS
59              
60             =cut
61              
62             =head2 new
63              
64             Returns a new typemap object. Takes an optional C parameter.
65             If set, the given file will be read. If the file doesn't exist, an empty typemap
66             is returned.
67              
68             Alternatively, if the C parameter is given, the supplied
69             string will be parsed instead of a file.
70              
71             =cut
72              
73             sub new {
74 1516     1516 1 884748 my $class = shift;
75 1516         6677 my %args = @_;
76              
77 1516 50 66     9643 if (defined $args{file} and defined $args{string}) {
78 0         0 die("Cannot handle both 'file' and 'string' arguments to constructor");
79             }
80              
81 1516         35998 my $self = bless {
82             file => undef,
83             %args,
84             typemap_section => [],
85             typemap_lookup => {},
86             input_section => [],
87             input_lookup => {},
88             output_section => [],
89             output_lookup => {},
90             } => $class;
91              
92 1516         8419 $self->_init();
93              
94 1516         9180 return $self;
95             }
96              
97             sub _init {
98 1516     1516   3622 my $self = shift;
99 1516 100 66     33116 if (defined $self->{string}) {
    100          
100 170         990 $self->_parse(\($self->{string}), $self->{lineno_offset}, $self->{fake_filename});
101 170         512 delete $self->{string};
102             }
103             elsif (defined $self->{file} and -e $self->{file}) {
104             open my $fh, '<', $self->{file}
105             or die "Cannot open typemap file '"
106 891 50       37340 . $self->{file} . "' for reading: $!";
107 891         7438 local $/ = undef;
108 891         32321 my $string = <$fh>;
109 891         10085 $self->_parse(\$string, $self->{lineno_offset}, $self->{file});
110             }
111             }
112              
113              
114             =head2 file
115              
116             Get/set the file that the typemap is written to when the
117             C method is called.
118              
119             =cut
120              
121             sub file {
122 0 0   0 1 0 $_[0]->{file} = $_[1] if @_ > 1;
123             $_[0]->{file}
124 0         0 }
125              
126             =head2 add_typemap
127              
128             Add a C entry to the typemap.
129              
130             Required named arguments: The C (e.g. C 'double'>)
131             and the C (e.g. C 'T_NV'>).
132              
133             Optional named arguments: C 1> forces removal/replacement of
134             existing C entries of the same C. C 1>
135             triggers a I<"first come first serve"> logic by which new entries that conflict
136             with existing entries are silently ignored.
137              
138             As an alternative to the named parameters usage, you may pass in
139             an C object as first argument, a copy of which will be
140             added to the typemap. In that case, only the C or C named parameters
141             may be used after the object. Example:
142              
143             $map->add_typemap($type_obj, replace => 1);
144              
145             =cut
146              
147             sub add_typemap {
148 90022     90022 1 111740 my $self = shift;
149 90022         107403 my $type;
150             my %args;
151              
152 90022 100       146651 if ((@_ % 2) == 1) {
153 90005         102812 my $orig = shift;
154 90005         146583 $type = $orig->new();
155 90005         171541 %args = @_;
156             }
157             else {
158 17         65 %args = @_;
159 17         34 my $ctype = $args{ctype};
160 17 50       45 die("Need ctype argument") if not defined $ctype;
161 17         26 my $xstype = $args{xstype};
162 17 50       38 die("Need xstype argument") if not defined $xstype;
163              
164             $type = ExtUtils::Typemaps::Type->new(
165             xstype => $xstype,
166 17         105 'prototype' => $args{'prototype'},
167             ctype => $ctype,
168             );
169             }
170              
171 90022 50 66     147101 if ($args{skip} and $args{replace}) {
172 0         0 die("Cannot use both 'skip' and 'replace'");
173             }
174              
175 90022 100       129243 if ($args{replace}) {
    100          
176 89436         151389 $self->remove_typemap(ctype => $type->ctype);
177             }
178             elsif ($args{skip}) {
179 1 50       3 return() if exists $self->{typemap_lookup}{$type->ctype};
180             }
181             else {
182 585         1494 $self->validate(typemap_xstype => $type->xstype, ctype => $type->ctype);
183             }
184              
185             # store
186 90020         116418 push @{$self->{typemap_section}}, $type;
  90020         157140  
187             # remember type for lookup, too.
188 90020         100884 $self->{typemap_lookup}{$type->tidy_ctype} = $#{$self->{typemap_section}};
  90020         192077  
189              
190 90020         314115 return 1;
191             }
192              
193             =head2 add_inputmap
194              
195             Add an C entry to the typemap.
196              
197             Required named arguments:
198             The C (e.g. C 'T_NV'>)
199             and the C to associate with it for input.
200              
201             Optional named arguments: C 1> forces removal/replacement of
202             existing C entries of the same C. C 1>
203             triggers a I<"first come first serve"> logic by which new entries that conflict
204             with existing entries are silently ignored.
205              
206             As an alternative to the named parameters usage, you may pass in
207             an C object as first argument, a copy of which will be
208             added to the typemap. In that case, only the C or C named parameters
209             may be used after the object. Example:
210              
211             $map->add_inputmap($type_obj, replace => 1);
212              
213             =cut
214              
215             sub add_inputmap {
216 75052     75052 1 84110 my $self = shift;
217 75052         87453 my $input;
218             my %args;
219              
220 75052 100       114597 if ((@_ % 2) == 1) {
221 75042         82362 my $orig = shift;
222 75042         116537 $input = $orig->new();
223 75042         121996 %args = @_;
224             }
225             else {
226 10         41 %args = @_;
227 10         18 my $xstype = $args{xstype};
228 10 50       24 die("Need xstype argument") if not defined $xstype;
229 10         17 my $code = $args{code};
230 10 50       25 die("Need code argument") if not defined $code;
231              
232 10         56 $input = ExtUtils::Typemaps::InputMap->new(
233             xstype => $xstype,
234             code => $code,
235             );
236             }
237              
238 75052 50 66     117744 if ($args{skip} and $args{replace}) {
239 0         0 die("Cannot use both 'skip' and 'replace'");
240             }
241              
242 75052 100       101205 if ($args{replace}) {
    100          
243 74891         116731 $self->remove_inputmap(xstype => $input->xstype);
244             }
245             elsif ($args{skip}) {
246 1 50       3 return() if exists $self->{input_lookup}{$input->xstype};
247             }
248             else {
249 160         479 $self->validate(inputmap_xstype => $input->xstype);
250             }
251              
252             # store
253 75052         90330 push @{$self->{input_section}}, $input;
  75052         116442  
254             # remember type for lookup, too.
255 75052         81874 $self->{input_lookup}{$input->xstype} = $#{$self->{input_section}};
  75052         146748  
256              
257 75052         150944 return 1;
258             }
259              
260             =head2 add_outputmap
261              
262             Add an C entry to the typemap.
263             Works exactly the same as C.
264              
265             =cut
266              
267             sub add_outputmap {
268 75145     75145 1 82808 my $self = shift;
269 75145         85881 my $output;
270             my %args;
271              
272 75145 100       110157 if ((@_ % 2) == 1) {
273 75137         78799 my $orig = shift;
274 75137         114644 $output = $orig->new();
275 75137         122448 %args = @_;
276             }
277             else {
278 8         23 %args = @_;
279 8         16 my $xstype = $args{xstype};
280 8 50       17 die("Need xstype argument") if not defined $xstype;
281 8         14 my $code = $args{code};
282 8 50       26 die("Need code argument") if not defined $code;
283              
284 8         39 $output = ExtUtils::Typemaps::OutputMap->new(
285             xstype => $xstype,
286             code => $code,
287             );
288             }
289              
290 75145 0 33     114173 if ($args{skip} and $args{replace}) {
291 0         0 die("Cannot use both 'skip' and 'replace'");
292             }
293              
294 75145 100       111021 if ($args{replace}) {
    50          
295 74932         118452 $self->remove_outputmap(xstype => $output->xstype);
296             }
297             elsif ($args{skip}) {
298 0 0       0 return() if exists $self->{output_lookup}{$output->xstype};
299             }
300             else {
301 213         503 $self->validate(outputmap_xstype => $output->xstype);
302             }
303              
304             # store
305 75145         89393 push @{$self->{output_section}}, $output;
  75145         115188  
306             # remember type for lookup, too.
307 75145         81321 $self->{output_lookup}{$output->xstype} = $#{$self->{output_section}};
  75145         144724  
308              
309 75145         144901 return 1;
310             }
311              
312             =head2 add_string
313              
314             Parses a string as a typemap and merge it into the typemap object.
315              
316             Required named argument: C to specify the string to parse.
317              
318             =cut
319              
320             sub add_string {
321 2     2 1 369 my $self = shift;
322 2         8 my %args = @_;
323 2 50       6 die("Need 'string' argument") if not defined $args{string};
324              
325             # no, this is not elegant.
326 2         9 my $other = ExtUtils::Typemaps->new(string => $args{string});
327 2         7 $self->merge(typemap => $other);
328             }
329              
330             =head2 remove_typemap
331              
332             Removes a C entry from the typemap.
333              
334             Required named argument: C to specify the entry to remove from the typemap.
335              
336             Alternatively, you may pass a single C object.
337              
338             =cut
339              
340             sub remove_typemap {
341 89436     89436 1 104376 my $self = shift;
342 89436         94868 my $ctype;
343 89436 50       134685 if (@_ > 1) {
344 89436         150515 my %args = @_;
345 89436         116979 $ctype = $args{ctype};
346 89436 50       135543 die("Need ctype argument") if not defined $ctype;
347 89436         134421 $ctype = tidy_type($ctype);
348             }
349             else {
350 0         0 $ctype = $_[0]->tidy_ctype;
351             }
352              
353 89436         180225 return $self->_remove($ctype, $self->{typemap_section}, $self->{typemap_lookup});
354             }
355              
356             =head2 remove_inputmap
357              
358             Removes an C entry from the typemap.
359              
360             Required named argument: C to specify the entry to remove from the typemap.
361              
362             Alternatively, you may pass a single C object.
363              
364             =cut
365              
366             sub remove_inputmap {
367 74891     74891 1 84319 my $self = shift;
368 74891         80361 my $xstype;
369 74891 50       104270 if (@_ > 1) {
370 74891         122985 my %args = @_;
371 74891         93347 $xstype = $args{xstype};
372 74891 50       132662 die("Need xstype argument") if not defined $xstype;
373             }
374             else {
375 0         0 $xstype = $_[0]->xstype;
376             }
377            
378 74891         127089 return $self->_remove($xstype, $self->{input_section}, $self->{input_lookup});
379             }
380              
381             =head2 remove_outputmap
382              
383             Removes an C entry from the typemap.
384              
385             Required named argument: C to specify the entry to remove from the typemap.
386              
387             Alternatively, you may pass a single C object.
388              
389             =cut
390              
391             sub remove_outputmap {
392 74932     74932 1 84501 my $self = shift;
393 74932         77124 my $xstype;
394 74932 50       99859 if (@_ > 1) {
395 74932         119468 my %args = @_;
396 74932         94330 $xstype = $args{xstype};
397 74932 50       122388 die("Need xstype argument") if not defined $xstype;
398             }
399             else {
400 0         0 $xstype = $_[0]->xstype;
401             }
402            
403 74932         124590 return $self->_remove($xstype, $self->{output_section}, $self->{output_lookup});
404             }
405              
406             sub _remove {
407 239259     239259   276180 my $self = shift;
408 239259         270102 my $rm = shift;
409 239259         244058 my $array = shift;
410 239259         246960 my $lookup = shift;
411              
412             # Just fetch the index of the item from the lookup table
413 239259         315718 my $index = $lookup->{$rm};
414 239259 100       416170 return() if not defined $index;
415              
416             # Nuke the item from storage
417 59377         83258 splice(@$array, $index, 1);
418              
419             # Decrement the storage position of all items thereafter
420 59377         381736 foreach my $key (keys %$lookup) {
421 2731140 100       3553982 if ($lookup->{$key} > $index) {
422 2669691         2925459 $lookup->{$key}--;
423             }
424             }
425 59377         198284 return();
426             }
427              
428             =head2 get_typemap
429              
430             Fetches an entry of the TYPEMAP section of the typemap.
431              
432             Mandatory named arguments: The C of the entry.
433              
434             Returns the C
435             object for the entry if found.
436              
437             =cut
438              
439             sub get_typemap {
440 1398     1398 1 2488 my $self = shift;
441 1398 100       3051 die("Need named parameters, got uneven number") if @_ % 2;
442              
443 1397         3307 my %args = @_;
444 1397         2376 my $ctype = $args{ctype};
445 1397 50       2422 die("Need ctype argument") if not defined $ctype;
446 1397         2240 $ctype = tidy_type($ctype);
447              
448 1397         2990 my $index = $self->{typemap_lookup}{$ctype};
449 1397 100       2457 return() if not defined $index;
450 1373         3791 return $self->{typemap_section}[$index];
451             }
452              
453             =head2 get_inputmap
454              
455             Fetches an entry of the INPUT section of the
456             typemap.
457              
458             Mandatory named arguments: The C of the
459             entry or the C of the typemap that can be used to find
460             the C. To wit, the following pieces of code
461             are equivalent:
462              
463             my $type = $typemap->get_typemap(ctype => $ctype)
464             my $input_map = $typemap->get_inputmap(xstype => $type->xstype);
465              
466             my $input_map = $typemap->get_inputmap(ctype => $ctype);
467              
468             Returns the C
469             object for the entry if found.
470              
471             =cut
472              
473             sub get_inputmap {
474 407     407 1 960 my $self = shift;
475 407 100       998 die("Need named parameters, got uneven number") if @_ % 2;
476              
477 406         1126 my %args = @_;
478 406         783 my $xstype = $args{xstype};
479 406         625 my $ctype = $args{ctype};
480 406 50 66     861 die("Need xstype or ctype argument")
481             if not defined $xstype
482             and not defined $ctype;
483 406 50 66     2218 die("Need xstype OR ctype arguments, not both")
484             if defined $xstype and defined $ctype;
485              
486 406 100       879 if (defined $ctype) {
487 2         6 my $tm = $self->get_typemap(ctype => $ctype);
488 2   66     12 $xstype = $tm && $tm->xstype;
489 2 100       10 return() if not defined $xstype;
490             }
491              
492 405         914 my $index = $self->{input_lookup}{$xstype};
493 405 100       884 return() if not defined $index;
494 400         1310 return $self->{input_section}[$index];
495             }
496              
497             =head2 get_outputmap
498              
499             Fetches an entry of the OUTPUT section of the
500             typemap.
501              
502             Mandatory named arguments: The C of the
503             entry or the C of the typemap that can be used to
504             resolve the C. (See above for an example.)
505              
506             Returns the C
507             object for the entry if found.
508              
509             =cut
510              
511             sub get_outputmap {
512 560     560 1 1227 my $self = shift;
513 560 100       1533 die("Need named parameters, got uneven number") if @_ % 2;
514              
515 559         1645 my %args = @_;
516 559         1123 my $xstype = $args{xstype};
517 559         967 my $ctype = $args{ctype};
518 559 50 66     2347 die("Need xstype or ctype argument")
519             if not defined $xstype
520             and not defined $ctype;
521 559 50 66     2270 die("Need xstype OR ctype arguments, not both")
522             if defined $xstype and defined $ctype;
523              
524 559 100       1240 if (defined $ctype) {
525 253         898 my $tm = $self->get_typemap(ctype => $ctype);
526 253   66     1921 $xstype = $tm && $tm->xstype;
527 253 100       747 return() if not defined $xstype;
528             }
529              
530 553         1092 my $index = $self->{output_lookup}{$xstype};
531 553 100       1327 return() if not defined $index;
532 545         1624 return $self->{output_section}[$index];
533             }
534              
535             =head2 write
536              
537             Write the typemap to a file. Optionally takes a C argument. If given, the
538             typemap will be written to the specified file. If not, the typemap is written
539             to the currently stored file name (see L above, this defaults to the file
540             it was read from if any).
541              
542             =cut
543              
544             sub write {
545 1     1 1 1025 my $self = shift;
546 1         4 my %args = @_;
547 1 50       7 my $file = defined $args{file} ? $args{file} : $self->file();
548 1 50       5 die("write() needs a file argument (or set the file name of the typemap using the 'file' method)")
549             if not defined $file;
550              
551 1 50       244 open my $fh, '>', $file
552             or die "Cannot open typemap file '$file' for writing: $!";
553 1         9 print $fh $self->as_string();
554 1         88 close $fh;
555             }
556              
557             =head2 as_string
558              
559             Generates and returns the string form of the typemap.
560              
561             =cut
562              
563             sub as_string {
564 24     24 1 3505 my $self = shift;
565 24         45 my $typemap = $self->{typemap_section};
566 24         34 my @code;
567 24         45 push @code, "TYPEMAP\n";
568 24         53 foreach my $entry (@$typemap) {
569             # type kind proto
570             # /^(.*?\S)\s+(\S+)\s*($ExtUtils::ParseXS::Constants::PrototypeRegexp*)$/o
571 38 50       119 push @code, $entry->ctype . "\t" . $entry->xstype
572             . ($entry->proto ne '' ? "\t".$entry->proto : '') . "\n";
573             }
574              
575 24         70 my $input = $self->{input_section};
576 24 100       58 if (@$input) {
577 17         28 push @code, "\nINPUT\n";
578 17         31 foreach my $entry (@$input) {
579 33         78 push @code, $entry->xstype, "\n", $entry->code, "\n";
580             }
581             }
582              
583 24         53 my $output = $self->{output_section};
584 24 100       53 if (@$output) {
585 15         29 push @code, "\nOUTPUT\n";
586 15         28 foreach my $entry (@$output) {
587 29         70 push @code, $entry->xstype, "\n", $entry->code, "\n";
588             }
589             }
590 24         208 return join '', @code;
591             }
592              
593             =head2 as_embedded_typemap
594              
595             Generates and returns the string form of the typemap with the
596             appropriate prefix around it for verbatim inclusion into an
597             XS file as an embedded typemap. This will return a string like
598              
599             TYPEMAP: <
600             ... typemap here (see as_string) ...
601             END_OF_TYPEMAP
602              
603             The method takes care not to use a HERE-doc end marker that
604             appears in the typemap string itself.
605              
606             =cut
607              
608             sub as_embedded_typemap {
609 6     6 1 12 my $self = shift;
610 6         16 my $string = $self->as_string;
611              
612 6         14 my @ident_cand = qw(END_TYPEMAP END_OF_TYPEMAP END);
613 6         6 my $icand = 0;
614 6         8 my $cand_suffix = "";
615 6         93 while ($string =~ /^\Q$ident_cand[$icand]$cand_suffix\E\s*$/m) {
616 0         0 $icand++;
617 0 0       0 if ($icand == @ident_cand) {
618 0         0 $icand = 0;
619 0         0 ++$cand_suffix;
620             }
621             }
622              
623 6         12 my $marker = "$ident_cand[$icand]$cand_suffix";
624 6         64 return "TYPEMAP: <<$marker;\n$string\n$marker\n";
625             }
626              
627             =head2 merge
628              
629             Merges a given typemap into the object. Note that a failed merge
630             operation leaves the object in an inconsistent state so clone it if necessary.
631              
632             Mandatory named arguments: Either C $another_typemap_obj>
633             or C $path_to_typemap_file> but not both.
634              
635             Optional arguments: C 1> to force replacement
636             of existing typemap entries without warning or C 1>
637             to skip entries that exist already in the typemap.
638              
639             =cut
640              
641             sub merge {
642 1052     1052 1 4137 my $self = shift;
643 1052         7644 my %args = @_;
644              
645 1052 50 66     12955 if (exists $args{typemap} and exists $args{file}) {
    50 66        
646 0         0 die("Need {file} OR {typemap} argument. Not both!");
647             }
648             elsif (not exists $args{typemap} and not exists $args{file}) {
649 0         0 die("Need {file} or {typemap} argument!");
650             }
651              
652 1052         2043 my @params;
653 1052 100       5923 push @params, 'replace' => $args{replace} if exists $args{replace};
654 1052 100       3150 push @params, 'skip' => $args{skip} if exists $args{skip};
655              
656 1052         2162 my $typemap = $args{typemap};
657 1052 100       2963 if (not defined $typemap) {
658 877         6661 $typemap = ref($self)->new(file => $args{file}, @params);
659             }
660              
661             # FIXME breaking encapsulation. Add accessor code.
662 1052         2742 foreach my $entry (@{$typemap->{typemap_section}}) {
  1052         4854  
663 44994         81263 $self->add_typemap( $entry, @params );
664             }
665              
666 1051         2056 foreach my $entry (@{$typemap->{input_section}}) {
  1051         2745  
667 37511         57270 $self->add_inputmap( $entry, @params );
668             }
669              
670 1051         1912 foreach my $entry (@{$typemap->{output_section}}) {
  1051         2842  
671 37559         57098 $self->add_outputmap( $entry, @params );
672             }
673              
674 1051         108399 return 1;
675             }
676              
677             =head2 is_empty
678              
679             Returns a bool indicating whether this typemap is entirely empty.
680              
681             =cut
682              
683             sub is_empty {
684 5     5 1 20 my $self = shift;
685              
686             return @{ $self->{typemap_section} } == 0
687             && @{ $self->{input_section} } == 0
688 5   100     11 && @{ $self->{output_section} } == 0;
689             }
690              
691             =head2 list_mapped_ctypes
692              
693             Returns a list of the C types that are mappable by
694             this typemap object.
695              
696             =cut
697              
698             sub list_mapped_ctypes {
699 7     7 1 13 my $self = shift;
700 7         12 return sort keys %{ $self->{typemap_lookup} };
  7         241  
701             }
702              
703             =head2 _get_typemap_hash
704              
705             Returns a hash mapping the C types to the XS types:
706              
707             {
708             'char **' => 'T_PACKEDARRAY',
709             'bool_t' => 'T_IV',
710             'AV *' => 'T_AVREF',
711             'InputStream' => 'T_IN',
712             'double' => 'T_DOUBLE',
713             # ...
714             }
715              
716             This is documented because it is used by C,
717             but it's not intended for general consumption. May be removed
718             at any time.
719              
720             =cut
721              
722             sub _get_typemap_hash {
723 4     4   29 my $self = shift;
724 4         9 my $lookup = $self->{typemap_lookup};
725 4         6 my $storage = $self->{typemap_section};
726              
727 4         5 my %rv;
728 4         23 foreach my $ctype (keys %$lookup) {
729 197         253 $rv{$ctype} = $storage->[ $lookup->{$ctype} ]->xstype;
730             }
731              
732 4         25 return \%rv;
733             }
734              
735             =head2 _get_inputmap_hash
736              
737             Returns a hash mapping the XS types (identifiers) to the
738             corresponding INPUT code:
739              
740             {
741             'T_CALLBACK' => ' $var = make_perl_cb_$type($arg)
742             ',
743             'T_OUT' => ' $var = IoOFP(sv_2io($arg))
744             ',
745             'T_REF_IV_PTR' => ' if (sv_isa($arg, \\"${ntype}\\")) {
746             # ...
747             }
748              
749             This is documented because it is used by C,
750             but it's not intended for general consumption. May be removed
751             at any time.
752              
753             =cut
754              
755             sub _get_inputmap_hash {
756 4     4   5 my $self = shift;
757 4         7 my $lookup = $self->{input_lookup};
758 4         5 my $storage = $self->{input_section};
759              
760 4         4 my %rv;
761 4         16 foreach my $xstype (keys %$lookup) {
762 97         141 $rv{$xstype} = $storage->[ $lookup->{$xstype} ]->code;
763              
764             # Squash trailing whitespace to one line break
765             # This isn't strictly necessary, but makes the output more similar
766             # to the original ExtUtils::ParseXS.
767 97         967 $rv{$xstype} =~ s/\s*\z/\n/;
768             }
769              
770 4         13 return \%rv;
771             }
772              
773              
774             =head2 _get_outputmap_hash
775              
776             Returns a hash mapping the XS types (identifiers) to the
777             corresponding OUTPUT code:
778              
779             {
780             'T_CALLBACK' => ' sv_setpvn($arg, $var.context.value().chp(),
781             $var.context.value().size());
782             ',
783             'T_OUT' => ' {
784             GV *gv = (GV *)sv_newmortal();
785             gv_init_pvn(gv, gv_stashpvs("$Package",1),
786             "__ANONIO__",10,0);
787             if ( do_open(gv, "+>&", 3, FALSE, 0, 0, $var) )
788             sv_setsv(
789             $arg,
790             sv_bless(newRV((SV*)gv), gv_stashpv("$Package",1))
791             );
792             else
793             $arg = &PL_sv_undef;
794             }
795             ',
796             # ...
797             }
798              
799             This is documented because it is used by C,
800             but it's not intended for general consumption. May be removed
801             at any time.
802              
803             =cut
804              
805             sub _get_outputmap_hash {
806 4     4   6 my $self = shift;
807 4         8 my $lookup = $self->{output_lookup};
808 4         8 my $storage = $self->{output_section};
809              
810 4         5 my %rv;
811 4         15 foreach my $xstype (keys %$lookup) {
812 92         127 $rv{$xstype} = $storage->[ $lookup->{$xstype} ]->code;
813              
814             # Squash trailing whitespace to one line break
815             # This isn't strictly necessary, but makes the output more similar
816             # to the original ExtUtils::ParseXS.
817 92         561 $rv{$xstype} =~ s/\s*\z/\n/;
818             }
819              
820 4         16 return \%rv;
821             }
822              
823             =head2 _get_prototype_hash
824              
825             Returns a hash mapping the C types of the typemap to their
826             corresponding prototypes.
827              
828             {
829             'char **' => '$',
830             'bool_t' => '$',
831             'AV *' => '$',
832             'InputStream' => '$',
833             'double' => '$',
834             # ...
835             }
836              
837             This is documented because it is used by C,
838             but it's not intended for general consumption. May be removed
839             at any time.
840              
841             =cut
842              
843             sub _get_prototype_hash {
844 4     4   71 my $self = shift;
845 4         6 my $lookup = $self->{typemap_lookup};
846 4         5 my $storage = $self->{typemap_section};
847              
848 4         5 my %rv;
849 4         20 foreach my $ctype (keys %$lookup) {
850 197   50     247 $rv{$ctype} = $storage->[ $lookup->{$ctype} ]->proto || '$';
851             }
852              
853 4         21 return \%rv;
854             }
855              
856              
857              
858             # make sure that the provided types wouldn't collide with what's
859             # in the object already.
860             sub validate {
861 958     958 0 1309 my $self = shift;
862 958         2928 my %args = @_;
863              
864 958 100 100     3748 if ( exists $args{ctype}
865             and exists $self->{typemap_lookup}{tidy_type($args{ctype})} )
866             {
867 1         13 die("Multiple definition of ctype '$args{ctype}' in TYPEMAP section");
868             }
869              
870 957 50 66     3008 if ( exists $args{inputmap_xstype}
871             and exists $self->{input_lookup}{$args{inputmap_xstype}} )
872             {
873 0         0 die("Multiple definition of xstype '$args{inputmap_xstype}' in INPUTMAP section");
874             }
875              
876 957 50 66     2938 if ( exists $args{outputmap_xstype}
877             and exists $self->{output_lookup}{$args{outputmap_xstype}} )
878             {
879 0         0 die("Multiple definition of xstype '$args{outputmap_xstype}' in OUTPUTMAP section");
880             }
881              
882 957         1986 return 1;
883             }
884              
885             =head2 clone
886              
887             Creates and returns a clone of a full typemaps object.
888              
889             Takes named parameters: If C is true,
890             the clone will share the actual individual type/input/outputmap objects,
891             but not share their storage. Use with caution. Without C,
892             the clone will be fully independent.
893              
894             =cut
895              
896             sub clone {
897 2     2 1 7 my $proto = shift;
898 2         4 my %args = @_;
899              
900 2         3 my $self;
901 2 100       4 if ($args{shallow}) {
902             $self = bless( {
903             %$proto,
904 1         2 typemap_section => [@{$proto->{typemap_section}}],
905 1         3 typemap_lookup => {%{$proto->{typemap_lookup}}},
906 1         2 input_section => [@{$proto->{input_section}}],
907 1         2 input_lookup => {%{$proto->{input_lookup}}},
908 1         1 output_section => [@{$proto->{output_section}}],
909 1         2 output_lookup => {%{$proto->{output_lookup}}},
  1         4  
910             } => ref($proto) );
911             }
912             else {
913             $self = bless( {
914             %$proto,
915 1         3 typemap_section => [map $_->new, @{$proto->{typemap_section}}],
916 1         3 typemap_lookup => {%{$proto->{typemap_lookup}}},
917 1         3 input_section => [map $_->new, @{$proto->{input_section}}],
918 1         12 input_lookup => {%{$proto->{input_lookup}}},
919 1         3 output_section => [map $_->new, @{$proto->{output_section}}],
920 1         3 output_lookup => {%{$proto->{output_lookup}}},
  1         6  
921             } => ref($proto) );
922             }
923              
924 2         6 return $self;
925             }
926              
927             =head2 tidy_type
928              
929             Function to (heuristically) canonicalize a C type in terms of white space.
930             Works to some degree with C++ types. For example,
931              
932             $halfway_canonical_type = tidy_type(' int * * const * ');
933              
934             returns C<'int ** const *'>.
935              
936             Moved from C.
937              
938             =cut
939              
940             sub tidy_type {
941 229222     229222 1 462554 local $_ = shift;
942              
943             # for templated C++ types, do some bit of flawed canonicalization
944             # wrt. templates at least
945 229222 100       426516 if (/[<>]/) {
946 4         28 s/\s*([<>])\s*/$1/g;
947 4         10 s/>>/> >/g;
948             }
949              
950             # rationalise any '*' by joining them into bunches and removing whitespace
951 229222         504060 s#\s*(\*+)\s*#$1#g;
952 229222         425255 s#(\*+)# $1 #g ;
953              
954             # trim leading & trailing whitespace
955 229222         340644 s/^\s+//; s/\s+$//;
  229222         338786  
956              
957             # change multiple whitespace into a single space
958 229222         384398 s/\s+/ /g;
959              
960 229222         505036 $_;
961             }
962              
963              
964              
965             sub _parse {
966 1061     1061   2449 my $self = shift;
967 1061         1951 my $stringref = shift;
968 1061         2925 my $lineno_offset = shift;
969 1061 100       4547 $lineno_offset = 0 if not defined $lineno_offset;
970 1061         2140 my $filename = shift;
971 1061 100       3229 $filename = '' if not defined $filename;
972              
973 1061         2194 my $replace = $self->{replace};
974 1061         2255 my $skip = $self->{skip};
975 1061 50 66     6267 die "Can only replace OR skip" if $replace and $skip;
976 1061         1886 my @add_params;
977 1061 100       4577 push @add_params, replace => 1 if $replace;
978 1061 50       2518 push @add_params, skip => 1 if $skip;
979              
980             # TODO comments should round-trip, currently ignoring
981             # TODO order of sections, multiple sections of same type
982             # Heavily influenced by ExtUtils::ParseXS
983 1061         2661 my $section = 'typemap';
984 1061         2043 my $lineno = $lineno_offset;
985 1061         3228 my $junk = "";
986 1061         1975 my $current = \$junk;
987 1061         2603 my @input_expr;
988             my @output_expr;
989 1061         13572 while ($$stringref =~ /^(.*)$/gcm) {
990 416620         627789 local $_ = $1;
991 416620         432066 ++$lineno;
992 416620         437347 chomp;
993 416620 100       648253 next if /^\s*#/;
994 404474 100       798657 if (/^INPUT\s*$/) {
    100          
    100          
995 1000         2163 $section = 'input';
996 1000         1819 $current = \$junk;
997 1000         2919 next;
998             }
999             elsif (/^OUTPUT\s*$/) {
1000 1002         1885 $section = 'output';
1001 1002         1654 $current = \$junk;
1002 1002         2738 next;
1003             }
1004             elsif (/^TYPEMAP\s*$/) {
1005 24         34 $section = 'typemap';
1006 24         46 $current = \$junk;
1007 24         87 next;
1008             }
1009            
1010 402448 100       744678 if ($section eq 'typemap') {
    100          
    100          
    100          
1011 48766         62890 my $line = $_;
1012 48766         74578 s/^\s+//; s/\s+$//;
  48766         84698  
1013 48766 100 66     152836 next if $_ eq '' or /^#/;
1014 45011 50       240815 my($type, $kind, $proto) = /^(.*?\S)\s+(\S+)\s*($ExtUtils::ParseXS::Constants::PrototypeRegexp*)$/o
1015             or warn("Warning: File '$filename' Line $lineno '$line' TYPEMAP entry needs 2 or 3 columns\n"),
1016             next;
1017              
1018 45011 100       81407 if (length($proto)) {
1019 110 50       179 warn("Warning: File '$filename' Line $lineno '$line' Invalid prototype '$proto'\n")
1020             unless _valid_proto_string($proto);
1021             }
1022             $self->add_typemap(
1023 45011 100       124264 ExtUtils::Typemaps::Type->new(
1024             xstype => $kind,
1025             (length($proto) ? (prototype => $proto) : ()),
1026             ctype => $type
1027             ),
1028             @add_params
1029             );
1030             } elsif (/^\s/) {
1031 278365         508300 s/\s+$//;
1032 278365 100       782755 $$current .= $$current eq '' ? $_ : "\n".$_;
1033             } elsif ($_ eq '') {
1034 208         595 next;
1035             } elsif ($section eq 'input') {
1036 37531         51121 s/\s+$//;
1037 37531         127087 push @input_expr, {xstype => $_, code => ''};
1038 37531         104019 $current = \$input_expr[-1]{code};
1039             } else { # output section
1040 37578         49407 s/\s+$//;
1041 37578         103217 push @output_expr, {xstype => $_, code => ''};
1042 37578         100684 $current = \$output_expr[-1]{code};
1043             }
1044              
1045             } # end while lines
1046              
1047 1061         3327 foreach my $inexpr (@input_expr) {
1048 37531         98498 $self->add_inputmap( ExtUtils::Typemaps::InputMap->new(%$inexpr), @add_params );
1049             }
1050 1061         2475 foreach my $outexpr (@output_expr) {
1051 37578         91599 $self->add_outputmap( ExtUtils::Typemaps::OutputMap->new(%$outexpr), @add_params );
1052             }
1053              
1054 1061         63348 return 1;
1055             }
1056              
1057             # taken from ExtUtils::ParseXS
1058             sub _valid_proto_string {
1059 110     110   143 my $string = shift;
1060 110 50       372 if ($string =~ /^$ExtUtils::ParseXS::Constants::PrototypeRegexp+$/o) {
1061 110         251 return $string;
1062             }
1063              
1064 0           return 0 ;
1065             }
1066              
1067             # taken from ExtUtils::ParseXS (C_string)
1068             sub _escape_backslashes {
1069 0     0     my $string = shift;
1070 0           $string =~ s[\\][\\\\]g;
1071 0           $string;
1072             }
1073              
1074             =head1 CAVEATS
1075              
1076             Inherits some evil code from C.
1077              
1078             =head1 SEE ALSO
1079              
1080             The parser is heavily inspired from the one in L.
1081              
1082             For details on typemaps: L, L.
1083              
1084             =head1 AUTHOR
1085              
1086             Steffen Mueller C<>
1087              
1088             =head1 COPYRIGHT & LICENSE
1089              
1090             Copyright 2009, 2010, 2011, 2012, 2013 Steffen Mueller
1091              
1092             This program is free software; you can redistribute it and/or
1093             modify it under the same terms as Perl itself.
1094              
1095             =cut
1096              
1097             1;
1098