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 16     16   1299809 use 5.006001;
  16         68  
3 16     16   102 use strict;
  16         36  
  16         696  
4 16     16   88 use warnings;
  16         30  
  16         113708  
5             our $VERSION = '3.61';
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 1143     1143 1 1399316 my $class = shift;
75 1143         6927 my %args = @_;
76              
77 1143 50 66     8327 if (defined $args{file} and defined $args{string}) {
78 0         0 die("Cannot handle both 'file' and 'string' arguments to constructor");
79             }
80              
81 1143         42618 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 1143         7595 $self->_init();
93              
94 1143         8176 return $self;
95             }
96              
97             sub _init {
98 1143     1143   3385 my $self = shift;
99 1143 100 66     26079 if (defined $self->{string}) {
    100          
100 148         1135 $self->_parse(\($self->{string}), $self->{lineno_offset}, $self->{fake_filename});
101 148         609 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 657 50       34565 . $self->{file} . "' for reading: $!";
107 657         6648 local $/ = undef;
108 657         31890 my $string = <$fh>;
109 657         10942 $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 66098     66098 1 109247 my $self = shift;
149 66098         107595 my $type;
150             my %args;
151              
152 66098 100       146441 if ((@_ % 2) == 1) {
153 66081         107689 my $orig = shift;
154 66081         156420 $type = $orig->new();
155 66081         194154 %args = @_;
156             }
157             else {
158 17         74 %args = @_;
159 17         39 my $ctype = $args{ctype};
160 17 50       59 die("Need ctype argument") if not defined $ctype;
161 17         32 my $xstype = $args{xstype};
162 17 50       52 die("Need xstype argument") if not defined $xstype;
163              
164             $type = ExtUtils::Typemaps::Type->new(
165             xstype => $xstype,
166 17         292 'prototype' => $args{'prototype'},
167             ctype => $ctype,
168             );
169             }
170              
171 66098 50 66     160100 if ($args{skip} and $args{replace}) {
172 0         0 die("Cannot use both 'skip' and 'replace'");
173             }
174              
175 66098 100       123797 if ($args{replace}) {
    100          
176 65540         161079 $self->remove_typemap(ctype => $type->ctype);
177             }
178             elsif ($args{skip}) {
179 1 50       5 return() if exists $self->{typemap_lookup}{$type->ctype};
180             }
181             else {
182 557         2181 $self->validate(typemap_xstype => $type->xstype, ctype => $type->ctype);
183             }
184              
185             # store
186 66096         128816 push @{$self->{typemap_section}}, $type;
  66096         183629  
187             # remember type for lookup, too.
188 66096         112640 $self->{typemap_lookup}{$type->tidy_ctype} = $#{$self->{typemap_section}};
  66096         224066  
189              
190 66096         416060 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 54902     54902 1 99588 my $self = shift;
217 54902         111657 my $input;
218             my %args;
219              
220 54902 100       113634 if ((@_ % 2) == 1) {
221 54892         76417 my $orig = shift;
222 54892         120184 $input = $orig->new();
223 54892         141469 %args = @_;
224             }
225             else {
226 10         39 %args = @_;
227 10         20 my $xstype = $args{xstype};
228 10 50       27 die("Need xstype argument") if not defined $xstype;
229 10         17 my $code = $args{code};
230 10 50       22 die("Need code argument") if not defined $code;
231              
232 10         69 $input = ExtUtils::Typemaps::InputMap->new(
233             xstype => $xstype,
234             code => $code,
235             );
236             }
237              
238 54902 50 66     128207 if ($args{skip} and $args{replace}) {
239 0         0 die("Cannot use both 'skip' and 'replace'");
240             }
241              
242 54902 100       107966 if ($args{replace}) {
    100          
243 54754         123563 $self->remove_inputmap(xstype => $input->xstype);
244             }
245             elsif ($args{skip}) {
246 1 50       5 return() if exists $self->{input_lookup}{$input->xstype};
247             }
248             else {
249 147         564 $self->validate(inputmap_xstype => $input->xstype);
250             }
251              
252             # store
253 54902         88050 push @{$self->{input_section}}, $input;
  54902         123126  
254             # remember type for lookup, too.
255 54902         77349 $self->{input_lookup}{$input->xstype} = $#{$self->{input_section}};
  54902         158192  
256              
257 54902         171567 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 54999     54999 1 82840 my $self = shift;
269 54999         86340 my $output;
270             my %args;
271              
272 54999 100       115546 if ((@_ % 2) == 1) {
273 54991         78811 my $orig = shift;
274 54991         119123 $output = $orig->new();
275 54991         127702 %args = @_;
276             }
277             else {
278 8         35 %args = @_;
279 8         43 my $xstype = $args{xstype};
280 8 50       33 die("Need xstype argument") if not defined $xstype;
281 8         18 my $code = $args{code};
282 8 50       29 die("Need code argument") if not defined $code;
283              
284 8         47 $output = ExtUtils::Typemaps::OutputMap->new(
285             xstype => $xstype,
286             code => $code,
287             );
288             }
289              
290 54999 0 33     128340 if ($args{skip} and $args{replace}) {
291 0         0 die("Cannot use both 'skip' and 'replace'");
292             }
293              
294 54999 100       102992 if ($args{replace}) {
    50          
295 54797         122721 $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 202         662 $self->validate(outputmap_xstype => $output->xstype);
302             }
303              
304             # store
305 54999         100311 push @{$self->{output_section}}, $output;
  54999         120075  
306             # remember type for lookup, too.
307 54999         75663 $self->{output_lookup}{$output->xstype} = $#{$self->{output_section}};
  54999         160784  
308              
309 54999         162286 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 632 my $self = shift;
322 2         10 my %args = @_;
323 2 50       9 die("Need 'string' argument") if not defined $args{string};
324              
325             # no, this is not elegant.
326 2         24 my $other = ExtUtils::Typemaps->new(string => $args{string});
327 2         8 $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 65540     65540 1 101576 my $self = shift;
342 65540         93499 my $ctype;
343 65540 50       127587 if (@_ > 1) {
344 65540         154908 my %args = @_;
345 65540         113583 $ctype = $args{ctype};
346 65540 50       136822 die("Need ctype argument") if not defined $ctype;
347 65540         139278 $ctype = tidy_type($ctype);
348             }
349             else {
350 0         0 $ctype = $_[0]->tidy_ctype;
351             }
352              
353 65540         220010 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 54754     54754 1 77081 my $self = shift;
368 54754         73923 my $xstype;
369 54754 50       98535 if (@_ > 1) {
370 54754         168972 my %args = @_;
371 54754         95861 $xstype = $args{xstype};
372 54754 50       133748 die("Need xstype argument") if not defined $xstype;
373             }
374             else {
375 0         0 $xstype = $_[0]->xstype;
376             }
377            
378 54754         141866 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 54797     54797 1 80033 my $self = shift;
393 54797         79291 my $xstype;
394 54797 50       104394 if (@_ > 1) {
395 54797         143855 my %args = @_;
396 54797         97623 $xstype = $args{xstype};
397 54797 50       135802 die("Need xstype argument") if not defined $xstype;
398             }
399             else {
400 0         0 $xstype = $_[0]->xstype;
401             }
402            
403 54797         142182 return $self->_remove($xstype, $self->{output_section}, $self->{output_lookup});
404             }
405              
406             sub _remove {
407 175091     175091   264571 my $self = shift;
408 175091         263463 my $rm = shift;
409 175091         245106 my $array = shift;
410 175091         231248 my $lookup = shift;
411              
412             # Just fetch the index of the item from the lookup table
413 175091         343167 my $index = $lookup->{$rm};
414 175091 100       461308 return() if not defined $index;
415              
416             # Nuke the item from storage
417 43347         87173 splice(@$array, $index, 1);
418              
419             # Decrement the storage position of all items thereafter
420 43347         509958 foreach my $key (keys %$lookup) {
421 1994106 100       3650123 if ($lookup->{$key} > $index) {
422 1948687         2897402 $lookup->{$key}--;
423             }
424             }
425 43347         242159 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 1233     1233 1 2920 my $self = shift;
441 1233 100       3498 die("Need named parameters, got uneven number") if @_ % 2;
442              
443 1232         4191 my %args = @_;
444 1232         2615 my $ctype = $args{ctype};
445 1232 50       2753 die("Need ctype argument") if not defined $ctype;
446 1232         2628 $ctype = tidy_type($ctype);
447              
448 1232         3400 my $index = $self->{typemap_lookup}{$ctype};
449 1232 100       2723 return() if not defined $index;
450 1216         4223 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 359     359 1 991 my $self = shift;
475 359 100       980 die("Need named parameters, got uneven number") if @_ % 2;
476              
477 358         1080 my %args = @_;
478 358         1366 my $xstype = $args{xstype};
479 358         640 my $ctype = $args{ctype};
480 358 50 66     836 die("Need xstype or ctype argument")
481             if not defined $xstype
482             and not defined $ctype;
483 358 50 66     2336 die("Need xstype OR ctype arguments, not both")
484             if defined $xstype and defined $ctype;
485              
486 358 100       1275 if (defined $ctype) {
487 2         10 my $tm = $self->get_typemap(ctype => $ctype);
488 2   66     13 $xstype = $tm && $tm->xstype;
489 2 100       12 return() if not defined $xstype;
490             }
491              
492 357         935 my $index = $self->{input_lookup}{$xstype};
493 357 100       850 return() if not defined $index;
494 352         1415 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 471     471 1 1245 my $self = shift;
513 471 100       1519 die("Need named parameters, got uneven number") if @_ % 2;
514              
515 470         1556 my %args = @_;
516 470         1153 my $xstype = $args{xstype};
517 470         1726 my $ctype = $args{ctype};
518 470 50 66     2569 die("Need xstype or ctype argument")
519             if not defined $xstype
520             and not defined $ctype;
521 470 50 66     2743 die("Need xstype OR ctype arguments, not both")
522             if defined $xstype and defined $ctype;
523              
524 470 100       1135 if (defined $ctype) {
525 211         1170 my $tm = $self->get_typemap(ctype => $ctype);
526 211   66     2189 $xstype = $tm && $tm->xstype;
527 211 100       801 return() if not defined $xstype;
528             }
529              
530 466         5532 my $index = $self->{output_lookup}{$xstype};
531 466 100       1298 return() if not defined $index;
532 462         1708 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 2043 my $self = shift;
546 1         5 my %args = @_;
547 1 50       5 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       216 open my $fh, '>', $file
552             or die "Cannot open typemap file '$file' for writing: $!";
553 1         6 print $fh $self->as_string();
554 1         49 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 4345 my $self = shift;
565 24         58 my $typemap = $self->{typemap_section};
566 24         45 my @code;
567 24         51 push @code, "TYPEMAP\n";
568 24         67 foreach my $entry (@$typemap) {
569             # type kind proto
570             # /^(.*?\S)\s+(\S+)\s*($ExtUtils::ParseXS::Constants::PrototypeRegexp*)$/o
571 38 50       111 push @code, $entry->ctype . "\t" . $entry->xstype
572             . ($entry->proto ne '' ? "\t".$entry->proto : '') . "\n";
573             }
574              
575 24         49 my $input = $self->{input_section};
576 24 100       91 if (@$input) {
577 17         38 push @code, "\nINPUT\n";
578 17         49 foreach my $entry (@$input) {
579 33         93 push @code, $entry->xstype, "\n", $entry->code, "\n";
580             }
581             }
582              
583 24         66 my $output = $self->{output_section};
584 24 100       91 if (@$output) {
585 15         32 push @code, "\nOUTPUT\n";
586 15         29 foreach my $entry (@$output) {
587 29         76 push @code, $entry->xstype, "\n", $entry->code, "\n";
588             }
589             }
590 24         241 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 15 my $self = shift;
610 6         24 my $string = $self->as_string;
611              
612 6         18 my @ident_cand = qw(END_TYPEMAP END_OF_TYPEMAP END);
613 6         12 my $icand = 0;
614 6         11 my $cand_suffix = "";
615 6         109 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         17 my $marker = "$ident_cand[$icand]$cand_suffix";
624 6         97 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 796     796 1 6275 my $self = shift;
643 796         7132 my %args = @_;
644              
645 796 50 66     11883 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 796         2255 my @params;
653 796 100       5013 push @params, 'replace' => $args{replace} if exists $args{replace};
654 796 100       3066 push @params, 'skip' => $args{skip} if exists $args{skip};
655              
656 796         2205 my $typemap = $args{typemap};
657 796 100       2508 if (not defined $typemap) {
658 643         13928 $typemap = ref($self)->new(file => $args{file}, @params);
659             }
660              
661             # FIXME breaking encapsulation. Add accessor code.
662 796         2224 foreach my $entry (@{$typemap->{typemap_section}}) {
  796         3267  
663 33032         85890 $self->add_typemap( $entry, @params );
664             }
665              
666 795         1751 foreach my $entry (@{$typemap->{input_section}}) {
  795         2991  
667 27436         60936 $self->add_inputmap( $entry, @params );
668             }
669              
670 795         1903 foreach my $entry (@{$typemap->{output_section}}) {
  795         2733  
671 27486         68004 $self->add_outputmap( $entry, @params );
672             }
673              
674 795         141151 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 26 my $self = shift;
685              
686             return @{ $self->{typemap_section} } == 0
687             && @{ $self->{input_section} } == 0
688 5   100     10 && @{ $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 3     3 1 18 my $self = shift;
700 3         10 return sort keys %{ $self->{typemap_lookup} };
  3         203  
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   41 my $self = shift;
724 4         12 my $lookup = $self->{typemap_lookup};
725 4         9 my $storage = $self->{typemap_section};
726              
727 4         11 my %rv;
728 4         40 foreach my $ctype (keys %$lookup) {
729 197         496 $rv{$ctype} = $storage->[ $lookup->{$ctype} ]->xstype;
730             }
731              
732 4         58 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   10 my $self = shift;
757 4         10 my $lookup = $self->{input_lookup};
758 4         9 my $storage = $self->{input_section};
759              
760 4         9 my %rv;
761 4         29 foreach my $xstype (keys %$lookup) {
762 97         353 $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         2096 $rv{$xstype} =~ s/\s*\z/\n/;
768             }
769              
770 4         37 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   8 my $self = shift;
807 4         12 my $lookup = $self->{output_lookup};
808 4         10 my $storage = $self->{output_section};
809              
810 4         8 my %rv;
811 4         26 foreach my $xstype (keys %$lookup) {
812 92         270 $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         1262 $rv{$xstype} =~ s/\s*\z/\n/;
818             }
819              
820 4         37 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   12 my $self = shift;
845 4         11 my $lookup = $self->{typemap_lookup};
846 4         9 my $storage = $self->{typemap_section};
847              
848 4         93 my %rv;
849 4         38 foreach my $ctype (keys %$lookup) {
850 197   50     462 $rv{$ctype} = $storage->[ $lookup->{$ctype} ]->proto || '$';
851             }
852              
853 4         47 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 906     906 0 1767 my $self = shift;
862 906         3891 my %args = @_;
863              
864 906 100 100     4493 if ( exists $args{ctype}
865             and exists $self->{typemap_lookup}{tidy_type($args{ctype})} )
866             {
867 1         23 die("Multiple definition of ctype '$args{ctype}' in TYPEMAP section");
868             }
869              
870 905 50 66     3190 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 905 50 66     3567 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 905         2337 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 11 my $proto = shift;
898 2         6 my %args = @_;
899              
900 2         4 my $self;
901 2 100       26 if ($args{shallow}) {
902             $self = bless( {
903             %$proto,
904 1         36 typemap_section => [@{$proto->{typemap_section}}],
905 1         6 typemap_lookup => {%{$proto->{typemap_lookup}}},
906 1         3 input_section => [@{$proto->{input_section}}],
907 1         4 input_lookup => {%{$proto->{input_lookup}}},
908 1         3 output_section => [@{$proto->{output_section}}],
909 1         4 output_lookup => {%{$proto->{output_lookup}}},
  1         9  
910             } => ref($proto) );
911             }
912             else {
913             $self = bless( {
914             %$proto,
915 1         8 typemap_section => [map $_->new, @{$proto->{typemap_section}}],
916 1         6 typemap_lookup => {%{$proto->{typemap_lookup}}},
917 1         6 input_section => [map $_->new, @{$proto->{input_section}}],
918 1         5 input_lookup => {%{$proto->{input_lookup}}},
919 1         21 output_section => [map $_->new, @{$proto->{output_section}}],
920 1         5 output_lookup => {%{$proto->{output_lookup}}},
  1         11  
921             } => ref($proto) );
922             }
923              
924 2         11 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 168888     168888 1 520993 local $_ = shift;
942              
943             # for templated C++ types, do some bit of flawed canonicalization
944             # wrt. templates at least
945 168888 100       494307 if (/[<>]/) {
946 4         41 s/\s*([<>])\s*/$1/g;
947 4         13 s/>>/> >/g;
948             }
949              
950             # rationalise any '*' by joining them into bunches and removing whitespace
951 168888         548747 s#\s*(\*+)\s*#$1#g;
952 168888         463885 s#(\*+)# $1 #g ;
953              
954             # trim leading & trailing whitespace
955 168888         377533 s/^\s+//; s/\s+$//;
  168888         367715  
956              
957             # change multiple whitespace into a single space
958 168888         416301 s/\s+/ /g;
959              
960 168888         607029 $_;
961             }
962              
963              
964              
965             sub _parse {
966 805     805   2149 my $self = shift;
967 805         1803 my $stringref = shift;
968 805         2408 my $lineno_offset = shift;
969 805 100       4470 $lineno_offset = 0 if not defined $lineno_offset;
970 805         2113 my $filename = shift;
971 805 100       2385 $filename = '' if not defined $filename;
972              
973 805         3040 my $replace = $self->{replace};
974 805         2047 my $skip = $self->{skip};
975 805 50 66     6201 die "Can only replace OR skip" if $replace and $skip;
976 805         2174 my @add_params;
977 805 100       5534 push @add_params, replace => 1 if $replace;
978 805 50       3034 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 805         2685 my $section = 'typemap';
984 805         1701 my $lineno = $lineno_offset;
985 805         2293 my $junk = "";
986 805         2536 my $current = \$junk;
987 805         2491 my @input_expr;
988             my @output_expr;
989 805         15399 while ($$stringref =~ /^(.*)$/gcm) {
990 304891         703880 local $_ = $1;
991 304891         423040 ++$lineno;
992 304891         436144 chomp;
993 304891 100       645522 next if /^\s*#/;
994 296021 100       826379 if (/^INPUT\s*$/) {
    100          
    100          
995 753         1930 $section = 'input';
996 753         1835 $current = \$junk;
997 753         2658 next;
998             }
999             elsif (/^OUTPUT\s*$/) {
1000 757         1754 $section = 'output';
1001 757         2172 $current = \$junk;
1002 757         3630 next;
1003             }
1004             elsif (/^TYPEMAP\s*$/) {
1005 24         72 $section = 'typemap';
1006 24         53 $current = \$junk;
1007 24         150 next;
1008             }
1009            
1010 294487 100       799705 if ($section eq 'typemap') {
    100          
    100          
    100          
1011 35862         62309 my $line = $_;
1012 35862         75941 s/^\s+//; s/\s+$//;
  35862         97911  
1013 35862 100 66     160302 next if $_ eq '' or /^#/;
1014 33049 50       274354 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 33049 100       90689 if (length($proto)) {
1019 110 50       249 warn("Warning: File '$filename' Line $lineno '$line' Invalid prototype '$proto'\n")
1020             unless _valid_proto_string($proto);
1021             }
1022             $self->add_typemap(
1023 33049 100       140760 ExtUtils::Typemaps::Type->new(
1024             xstype => $kind,
1025             (length($proto) ? (prototype => $proto) : ()),
1026             ctype => $type
1027             ),
1028             @add_params
1029             );
1030             } elsif (/^\s/) {
1031 203461         545227 s/\s+$//;
1032 203461 100       888551 $$current .= $$current eq '' ? $_ : "\n".$_;
1033             } elsif ($_ eq '') {
1034 203         1807 next;
1035             } elsif ($section eq 'input') {
1036 27456         51834 s/\s+$//;
1037 27456         193276 push @input_expr, {xstype => $_, code => ''};
1038 27456         113151 $current = \$input_expr[-1]{code};
1039             } else { # output section
1040 27505         50411 s/\s+$//;
1041 27505         136552 push @output_expr, {xstype => $_, code => ''};
1042 27505         131751 $current = \$output_expr[-1]{code};
1043             }
1044              
1045             } # end while lines
1046              
1047 805         4321 foreach my $inexpr (@input_expr) {
1048 27456         109602 $self->add_inputmap( ExtUtils::Typemaps::InputMap->new(%$inexpr), @add_params );
1049             }
1050 805         5116 foreach my $outexpr (@output_expr) {
1051 27505         103381 $self->add_outputmap( ExtUtils::Typemaps::OutputMap->new(%$outexpr), @add_params );
1052             }
1053              
1054 805         74558 return 1;
1055             }
1056              
1057             # taken from ExtUtils::ParseXS
1058             sub _valid_proto_string {
1059 110     110   180 my $string = shift;
1060 110 50       540 if ($string =~ /^$ExtUtils::ParseXS::Constants::PrototypeRegexp+$/o) {
1061 110         344 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