File Coverage

blib/lib/ExtUtils/ParseXS/Utilities.pm
Criterion Covered Total %
statement 113 115 98.2
branch 36 38 94.7
condition 1 2 50.0
subroutine 22 22 100.0
pod 15 16 93.7
total 187 193 96.8


line stmt bran cond sub pod time code
1             package ExtUtils::ParseXS::Utilities;
2 24     24   793306 use strict;
  24         56  
  24         1117  
3 24     24   152 use warnings;
  24         53  
  24         1774  
4 24     24   231 use Exporter;
  24         83  
  24         1397  
5 24     24   3210 use File::Spec;
  24         67  
  24         706  
6 24     24   3320 use ExtUtils::ParseXS::Constants ();
  24         57  
  24         51280  
7              
8             our $VERSION = '3.61';
9              
10             our (@ISA, @EXPORT_OK);
11             @ISA = qw(Exporter);
12             @EXPORT_OK = qw(
13             standard_typemap_locations
14             trim_whitespace
15             C_string
16             valid_proto_string
17             process_typemaps
18             map_type
19             set_cond
20             Warn
21             WarnHint
22             current_line_number
23             blurt
24             death
25             check_conditional_preprocessor_statements
26             escape_file_for_line_directive
27             report_typemap_failure
28             looks_like_MODULE_line
29             );
30              
31             =head1 NAME
32              
33             ExtUtils::ParseXS::Utilities - Subroutines used with ExtUtils::ParseXS
34              
35             =head1 SYNOPSIS
36              
37             use ExtUtils::ParseXS::Utilities qw(
38             standard_typemap_locations
39             trim_whitespace
40             C_string
41             valid_proto_string
42             process_typemaps
43             map_type
44             set_cond
45             Warn
46             blurt
47             death
48             check_conditional_preprocessor_statements
49             escape_file_for_line_directive
50             report_typemap_failure
51             );
52              
53             =head1 SUBROUTINES
54              
55             The following functions are not considered to be part of the public interface.
56             They are documented here for the benefit of future maintainers of this module.
57              
58             =head2 C
59              
60             =over 4
61              
62             =item * Purpose
63              
64             Returns a standard list of filepaths where F files may be found.
65             This will typically be something like:
66              
67             map("$_/ExtUtils/typemap", reverse @INC),
68             qw(
69             ../../../../lib/ExtUtils/typemap
70             ../../../../typemap
71             ../../../lib/ExtUtils/typemap
72             ../../../typemap
73             ../../lib/ExtUtils/typemap
74             ../../typemap
75             ../lib/ExtUtils/typemap
76             ../typemap
77             typemap
78             )
79              
80             but the style of the pathnames may vary with OS. Note that the value to
81             use for C<@INC> is passed as an array reference, and can be something
82             other than C<@INC> itself.
83              
84             Pathnames are returned in the order they are expected to be processed;
85             this means that later files will update or override entries found in
86             earlier files. So in particular, F in the current directory has
87             highest priority. C<@INC> is searched in reverse order so that earlier
88             entries in C<@INC> are processed later and so have higher priority.
89              
90             The values of C<-typemap> switches are not used here; they should be added
91             by the caller to the list of pathnames returned by this function.
92              
93             =item * Arguments
94              
95             my @stl = standard_typemap_locations(\@INC);
96              
97             A single argument: a reference to an array to use as if it were C<@INC>.
98              
99             =item * Return Value
100              
101             A list of F pathnames.
102              
103             =back
104              
105             =cut
106              
107             sub standard_typemap_locations {
108 321     321 1 187122 my $include_ref = shift;
109              
110 321         750 my @tm;
111              
112             # See function description above for why 'reverse' is used here.
113 321         755 foreach my $dir (reverse @{$include_ref}) {
  321         15923  
114 2878         66039 my $file = File::Spec->catfile($dir, ExtUtils => 'typemap');
115 2878         13493 push @tm, $file;
116             }
117              
118 321         6116 my $updir = File::Spec->updir();
119 321         16066 foreach my $dir (
120             File::Spec->catdir(($updir) x 4),
121             File::Spec->catdir(($updir) x 3),
122             File::Spec->catdir(($updir) x 2),
123             File::Spec->catdir(($updir) x 1),
124             ) {
125 1284         20690 push @tm, File::Spec->catfile($dir, lib => ExtUtils => 'typemap');
126 1284         13625 push @tm, File::Spec->catfile($dir, 'typemap');
127             }
128              
129 321         2641 push @tm, 'typemap';
130              
131 321         9629 return @tm;
132             }
133              
134             =head2 C
135              
136             =over 4
137              
138             =item * Purpose
139              
140             Perform an in-place trimming of leading and trailing whitespace from the
141             first argument provided to the function.
142              
143             =item * Argument
144              
145             trim_whitespace($arg);
146              
147             =item * Return Value
148              
149             None. Remember: this is an I modification of the argument.
150              
151             =back
152              
153             =cut
154              
155             sub trim_whitespace {
156 1219     1219 1 500121 $_[0] =~ s/^\s+|\s+$//go;
157             }
158              
159             =head2 C
160              
161             =over 4
162              
163             =item * Purpose
164              
165             Escape backslashes (C<\>) in prototype strings.
166              
167             =item * Arguments
168              
169             $ProtoThisXSUB = C_string($_);
170              
171             String needing escaping.
172              
173             =item * Return Value
174              
175             Properly escaped string.
176              
177             =back
178              
179             =cut
180              
181             sub C_string {
182 240     240 1 1827 my($string) = @_;
183              
184 240         506 $string =~ s[\\][\\\\]g;
185 240         1327 $string;
186             }
187              
188             =head2 C
189              
190             =over 4
191              
192             =item * Purpose
193              
194             Validate prototype string.
195              
196             =item * Arguments
197              
198             String needing checking.
199              
200             =item * Return Value
201              
202             Upon success, returns the same string passed as argument.
203              
204             Upon failure, returns C<0>.
205              
206             =back
207              
208             =cut
209              
210             sub valid_proto_string {
211 15     15 1 214620 my ($string) = @_;
212              
213 15 100       243 if ( $string =~ /^$ExtUtils::ParseXS::Constants::PrototypeRegexp+$/ ) {
214 12         49 return $string;
215             }
216              
217 3         25 return 0;
218             }
219              
220             =head2 C
221              
222             =over 4
223              
224             =item * Purpose
225              
226             Process all typemap files. Reads in any typemap files specified explicitly
227             with C<-typemap> switches or similar, plus any typemap files found in
228             standard locations relative to C<@INC> and the current directory.
229              
230             =item * Arguments
231              
232             my $typemaps_object = process_typemaps( $args{typemap}, $pwd );
233              
234             The first argument is the C element from C<%args>; the second is
235             the current working directory (which is only needed for error messages).
236              
237             =item * Return Value
238              
239             Upon success, returns an L object which contains the
240             accumulated results of all processed typemap files.
241              
242             =back
243              
244             =cut
245              
246             sub process_typemaps {
247 323     323 1 246558 my ($tmap, $pwd) = @_;
248              
249 323         4078 my @tm = standard_typemap_locations( \@INC );
250              
251 323 100       1643 my @explicit = ref $tmap ? @{$tmap} : ($tmap);
  322         969  
252 323         1786 foreach my $typemap (@explicit) {
253 7 100       260 die "Can't find $typemap in $pwd\n" unless -r $typemap;
254             }
255 321         731 push @tm, @explicit;
256              
257 321         16655 require ExtUtils::Typemaps;
258 321         9051 my $typemap = ExtUtils::Typemaps->new;
259 321         1221 foreach my $typemap_loc (@tm) {
260 5713 100       77791 next unless -f $typemap_loc;
261             # skip directories, binary files etc.
262 642 50       72163 warn("Warning: ignoring non-text typemap file '$typemap_loc'\n"), next
263             unless -T $typemap_loc;
264              
265 642         10668 $typemap->merge(file => $typemap_loc, replace => 1);
266             }
267              
268 321         6611 return $typemap;
269             }
270              
271              
272             =head2 C
273              
274             Returns a mapped version of the C type C<$type>. In particular, it
275             converts C to C, converts the special C
276             into C, and inserts C<$varname> (if present) into any function
277             pointer type. So C<...(*)...> becomes C<...(* foo)...>.
278              
279             =cut
280              
281             sub map_type {
282 640     640 1 5226 my ExtUtils::ParseXS $self = shift;
283 640         1535 my ($type, $varname) = @_;
284              
285             # C++ has :: in types too so skip this
286 640 100       2741 $type =~ tr/:/_/ unless $self->{config_RetainCplusplusHierarchicalTypes};
287              
288             # map the special return type 'array(type, n)' to 'type *'
289 640         1661 $type =~ s/^array\(([^,]*),(.*)\).*/$1 */s;
290              
291 640 100       1578 if ($varname) {
292 6 100       26 if ($type =~ / \( \s* \* (?= \s* \) ) /xg) {
293 2         13 (substr $type, pos $type, 0) = " $varname ";
294             }
295             else {
296 4         7 $type .= "\t$varname";
297             }
298             }
299 640         3439 return $type;
300             }
301              
302              
303             =head2 C
304              
305             =over 4
306              
307             =item * Purpose
308              
309             Return a string containing a snippet of C code which tests for the 'wrong
310             number of arguments passed' condition, depending on whether there are
311             default arguments or ellipsis.
312              
313             =item * Arguments
314              
315             C true if the xsub's signature has a trailing C<, ...>.
316              
317             C<$min_args> the smallest number of args which may be passed.
318              
319             C<$num_args> the number of parameters in the signature.
320              
321             =item * Return Value
322              
323             The text of a short C code snippet.
324              
325             =back
326              
327             =cut
328              
329             sub set_cond {
330 354     354 1 2017 my ($ellipsis, $min_args, $num_args) = @_;
331 354         726 my $cond;
332 354 100       1466 if ($ellipsis) {
    100          
333 11 100       61 $cond = ($min_args ? qq(items < $min_args) : 0);
334             }
335             elsif ($min_args == $num_args) {
336 328         1002 $cond = qq(items != $min_args);
337             }
338             else {
339 15         57 $cond = qq(items < $min_args || items > $num_args);
340             }
341 354         2499 return $cond;
342             }
343              
344             =head2 C
345              
346             =over 4
347              
348             =item * Purpose
349              
350             Figures out the current line number in the XS file.
351              
352             =item * Arguments
353              
354             C<$self>
355              
356             =item * Return Value
357              
358             The current line number.
359              
360             =back
361              
362             =cut
363              
364             sub current_line_number {
365 279     279 1 1199 my ExtUtils::ParseXS $self = shift;
366             # NB: until the first MODULE line is encountered, $self->{line_no} etc
367             # won't have been populated
368 279         1795 my $line_number = @{$self->{line_no}}
369 278         762 ? $self->{line_no}->[@{ $self->{line_no} } - @{ $self->{line} } -1]
  278         1810  
370 279 100       801 : $self->{lastline_no};
371 279         2994 return $line_number;
372             }
373              
374              
375              
376             =head2 Error handling methods
377              
378             There are four main methods for reporting warnings and errors.
379              
380             =over
381              
382             =item C<< $self->Warn(@messages) >>
383              
384             This is equivalent to:
385              
386             warn "@messages in foo.xs, line 123\n";
387              
388             The file and line number are based on the file currently being parsed. It
389             is intended for use where you wish to warn, but can continue parsing and
390             still generate a correct C output file.
391              
392             =item C<< $self->blurt(@messages) >>
393              
394             This is equivalent to C, except that it also increments the internal
395             error count (which can be retrieved with C). It is
396             used to report an error, but where parsing can continue (so typically for
397             a semantic error rather than a syntax error). It is expected that the
398             caller will eventually signal failure in some fashion. For example,
399             C has this as its last line:
400              
401             exit($self->report_error_count() ? 1 : 0);
402              
403             =item C<< $self->death(@messages) >>
404              
405             This normally equivalent to:
406              
407             $self->Warn(@messages);
408             exit(1);
409              
410             It is used for something like a syntax error, where parsing can't
411             continue. However, this is inconvenient for testing purposes, as the
412             error can't be trapped. So if C<$self> is created with the C
413             flag, or if C<$ExtUtils::ParseXS::DIE_ON_ERROR> is true when process_file()
414             is called, then instead it will die() with that message.
415              
416             =item C<< $self->WarnHint(@messages, $hints) >>
417              
418             This is a more obscure twin to C, which does the same as C,
419             but afterwards, outputs any lines contained in the C<$hints> string, with
420             each line wrapped in parentheses. For example:
421              
422             $self->WarnHint(@messages,
423             "Have you set the foo switch?\nSee the manual for further info");
424              
425             =back
426              
427             =cut
428              
429              
430             # see L above
431              
432             sub Warn {
433 94     94 1 1821 my ExtUtils::ParseXS $self = shift;
434 94         770 $self->WarnHint(@_,undef);
435             }
436              
437              
438             # see L above
439              
440             sub WarnHint {
441 101     101 1 686 warn _MsgHint(@_);
442             }
443              
444              
445             # see L above
446              
447             sub _MsgHint {
448 134     134   506 my ExtUtils::ParseXS $self = shift;
449 134         780 my $hint = pop;
450 134         867 my $warn_line_number = $self->current_line_number();
451 134         1043 my $ret = join("",@_) . " in $self->{in_filename}, line $warn_line_number\n";
452 134 100       730 if ($hint) {
453 3         34 $ret .= " ($_)\n" for split /\n/, $hint;
454             }
455 134         1308 return $ret;
456             }
457              
458              
459             # see L above
460              
461             sub blurt {
462 68     68 1 880 my ExtUtils::ParseXS $self = shift;
463 68         553 $self->Warn(@_);
464 68         1156 $self->{error_count}++
465             }
466              
467              
468             # see L above
469              
470             sub death {
471 33     33 1 113 my ExtUtils::ParseXS $self = $_[0];
472 33         1433 my $message = _MsgHint(@_,"");
473 33 50       238 if ($self->{config_die_on_error}) {
474 33         2257 die $message;
475             } else {
476 0         0 warn $message;
477             }
478 0         0 exit 1;
479             }
480              
481              
482             =head2 C
483              
484             =over 4
485              
486             =item * Purpose
487              
488             Warn if the lines in C<< @{ $self->{line} } >> don't have balanced C<#if>,
489             C etc.
490              
491             =item * Arguments
492              
493             None
494              
495             =item * Return Value
496              
497             None
498              
499             =back
500              
501             =cut
502              
503             sub check_conditional_preprocessor_statements {
504 369     369 1 174087 my ExtUtils::ParseXS $self = $_[0];
505 369         733 my @cpp = grep(/^\#\s*(?:if|e\w+)/, @{ $self->{line} });
  369         2919  
506 369 100       2803 if (@cpp) {
507 5         6 my $cpplevel;
508 5         10 for my $cpp (@cpp) {
509 13 100       48 if ($cpp =~ /^\#\s*if/) {
    100          
    100          
510 4         6 $cpplevel++;
511             }
512             elsif (!$cpplevel) {
513 2         10 $self->Warn("Warning: #else/elif/endif without #if in this function");
514 2         7 return;
515             }
516             elsif ($cpp =~ /^\#\s*endif/) {
517 3         4 $cpplevel--;
518             }
519             }
520 3 100       15 $self->Warn("Warning: #if without #endif in this function") if $cpplevel;
521             }
522             }
523              
524             =head2 C
525              
526             =over 4
527              
528             =item * Purpose
529              
530             Escapes a given code source name (typically a file name but can also
531             be a command that was read from) so that double-quotes and backslashes are escaped.
532              
533             =item * Arguments
534              
535             A string.
536              
537             =item * Return Value
538              
539             A string with escapes for double-quotes and backslashes.
540              
541             =back
542              
543             =cut
544              
545             sub escape_file_for_line_directive {
546 405     405 1 1796 my $string = shift;
547 405         1251 $string =~ s/\\/\\\\/g;
548 405         1158 $string =~ s/"/\\"/g;
549 405         1999 return $string;
550             }
551              
552             =head2 C
553              
554             =over 4
555              
556             =item * Purpose
557              
558             Do error reporting for missing typemaps.
559              
560             =item * Arguments
561              
562             The C object.
563              
564             An C object.
565              
566             The string that represents the C type that was not found in the typemap.
567              
568             Optionally, the string C or C to choose
569             whether the error is immediately fatal or not. Default: C
570              
571             =item * Return Value
572              
573             Returns nothing. Depending on the arguments, this
574             may call C or C, the former of which is
575             fatal.
576              
577             =back
578              
579             =cut
580              
581             sub report_typemap_failure {
582 3     3 1 22 my ExtUtils::ParseXS $self = shift;
583 3         21 my ($tm, $ctype, $error_method) = @_;
584 3   50     61 $error_method ||= 'blurt';
585              
586 3         35 my @avail_ctypes = $tm->list_mapped_ctypes;
587              
588 3         83 my $err = "Could not find a typemap for C type '$ctype'.\n"
589             . "The following C types are mapped by the current typemap:\n'"
590             . join("', '", @avail_ctypes) . "'\n";
591              
592 3         37 $self->$error_method($err);
593 3         41 return();
594             }
595              
596             =head2 C
597              
598             Returns true if the passed line looks like an attempt to be a MODULE line.
599             Note that it doesn't check for valid syntax. This allows the caller to do
600             its own parsing of the line, providing some sort of 'invalid MODULE line'
601             check. As compared with thinking that its not a MODULE line if its syntax
602             is slightly off, leading instead to some weird error about a bad start to
603             an XSUB or something.
604              
605             In particular, a line starting C returns true, because it's
606             likely to be an attempt by the programmer to write a MODULE line, even
607             though it's invalid syntax.
608              
609             =cut
610              
611             sub looks_like_MODULE_line {
612 1689     1689 0 3966 my $line = shift;
613 1689         75053 $line =~ /^MODULE\s*[=:]/;
614             }
615              
616              
617              
618             1;
619              
620             # vim: ts=2 sw=2 et: