File Coverage

blib/lib/ExtUtils/Constant/XS.pm
Criterion Covered Total %
statement 93 98 94.9
branch 42 50 84.0
condition 6 9 66.6
subroutine 21 21 100.0
pod 4 17 23.5
total 166 195 85.1


line stmt bran cond sub pod time code
1             package ExtUtils::Constant::XS;
2              
3 1     1   5 use strict;
  1         2  
  1         26  
4 1     1   5 use vars qw($VERSION %XS_Constant %XS_TypeSet @ISA @EXPORT_OK $is_perl56);
  1         1  
  1         52  
5 1     1   4 use Carp;
  1         2  
  1         40  
6 1     1   5 use ExtUtils::Constant::Utils 'perl_stringify';
  1         1  
  1         878  
7             require ExtUtils::Constant::Base;
8              
9              
10             @ISA = qw(ExtUtils::Constant::Base Exporter);
11             @EXPORT_OK = qw(%XS_Constant %XS_TypeSet);
12              
13             $VERSION = '0.24_01';
14              
15             $is_perl56 = ($] < 5.007 && $] > 5.005_50);
16              
17             =head1 NAME
18              
19             ExtUtils::Constant::XS - generate C code for XS modules' constants.
20              
21             =head1 SYNOPSIS
22              
23             require ExtUtils::Constant::XS;
24              
25             =head1 DESCRIPTION
26              
27             ExtUtils::Constant::XS overrides ExtUtils::Constant::Base to generate C
28             code for XS modules' constants.
29              
30             =head1 BUGS
31              
32             Nothing is documented.
33              
34             Probably others.
35              
36             =head1 AUTHOR
37              
38             Nicholas Clark based on the code in C by Larry Wall and
39             others
40              
41             =cut
42              
43             # '' is used as a flag to indicate non-ascii macro names, and hence the need
44             # to pass in the utf8 on/off flag.
45             %XS_Constant = (
46             '' => '',
47             IV => 'PUSHi(iv)',
48             UV => 'PUSHu((UV)iv)',
49             NV => 'PUSHn(nv)',
50             PV => 'PUSHp(pv, strlen(pv))',
51             PVN => 'PUSHp(pv, iv)',
52             SV => 'PUSHs(sv)',
53             YES => 'PUSHs(&PL_sv_yes)',
54             NO => 'PUSHs(&PL_sv_no)',
55             UNDEF => '', # implicit undef
56             );
57              
58             %XS_TypeSet = (
59             IV => '*iv_return = ',
60             UV => '*iv_return = (IV)',
61             NV => '*nv_return = ',
62             PV => '*pv_return = ',
63             PVN => ['*pv_return = ', '*iv_return = (IV)'],
64             SV => '*sv_return = ',
65             YES => undef,
66             NO => undef,
67             UNDEF => undef,
68             );
69              
70             sub header {
71 13     13 1 32 my $start = 1;
72 13         24 my @lines;
73 13         59 push @lines, "#define PERL_constant_NOTFOUND\t$start\n"; $start++;
  13         42  
74 13         38 push @lines, "#define PERL_constant_NOTDEF\t$start\n"; $start++;
  13         23  
75 13         181 foreach (sort keys %XS_Constant) {
76 130 100       224 next if $_ eq '';
77 117         234 push @lines, "#define PERL_constant_IS$_\t$start\n"; $start++;
  117         163  
78             }
79 13         52 push @lines, << 'EOT';
80              
81             #ifndef NVTYPE
82             typedef double NV; /* 5.6 and later define NVTYPE, and typedef NV to it. */
83             #endif
84             #ifndef aTHX_
85             #define aTHX_ /* 5.6 or later define this for threading support. */
86             #endif
87             #ifndef pTHX_
88             #define pTHX_ /* 5.6 or later define this for threading support. */
89             #endif
90             #ifndef SvRV_set
91             #define SvRV_set(sv,val) SvRV(sv) = (val)
92             #endif
93             EOT
94              
95 13         141 return join '', @lines;
96             }
97              
98             sub valid_type {
99 315     315 0 501 my ($self, $type) = @_;
100 315         859 return exists $XS_TypeSet{$type};
101             }
102              
103             # This might actually be a return statement
104             sub assignment_clause_for_type {
105 74     74 0 120 my $self = shift;
106 74         96 my $args = shift;
107 74         122 my $type = $args->{type};
108 74         126 my $typeset = $XS_TypeSet{$type};
109 74 100       174 if (ref $typeset) {
    100          
110 1 50       4 die "Type $type is aggregate, but only single value given"
111             if @_ == 1;
112 1         3 return map {"$typeset->[$_]$_[$_];"} 0 .. $#$typeset;
  2         7  
113             } elsif (defined $typeset) {
114 70 50       126 confess "Aggregate value given for type $type"
115             if @_ > 1;
116 70         236 return "$typeset$_[0];";
117             }
118 3         7 return ();
119             }
120              
121             sub return_statement_for_type {
122 74     74 0 127 my ($self, $type) = @_;
123             # In the future may pass in an options hash
124 74 50       133 $type = $type->{type} if ref $type;
125 74         170 "return PERL_constant_IS$type;";
126             }
127              
128             sub return_statement_for_notdef {
129             # my ($self) = @_;
130 56     56 0 106 "return PERL_constant_NOTDEF;";
131             }
132              
133             sub return_statement_for_notfound {
134             # my ($self) = @_;
135 17     17 0 39 "return PERL_constant_NOTFOUND;";
136             }
137              
138             sub default_type {
139 1     1 1 8 'IV';
140             }
141              
142             sub macro_from_name {
143 469     469 0 790 my ($self, $item) = @_;
144 469         678 my $macro = $item->{name};
145 469 50       770 $macro = $item->{value} unless defined $macro;
146 469         833 $macro;
147             }
148              
149             sub macro_from_item {
150 563     563 0 886 my ($self, $item) = @_;
151 563         815 my $macro = $item->{macro};
152 563 100       1176 $macro = $self->macro_from_name($item) unless defined $macro;
153 563         1146 $macro;
154             }
155              
156             # Keep to the traditional perl source macro
157             sub memEQ {
158 18     18 0 43 "memEQ";
159             }
160              
161             sub params {
162 33     33 1 72 my ($self, $what) = @_;
163 33         130 foreach (sort keys %$what) {
164 74 50       153 warn "ExtUtils::Constant doesn't know how to handle values of type $_" unless defined $XS_Constant{$_};
165             }
166 33         75 my $params = {};
167 33 100       82 $params->{''} = 1 if $what->{''};
168 33 100 66     125 $params->{IV} = 1 if $what->{IV} || $what->{UV} || $what->{PVN};
      66        
169 33 100       78 $params->{NV} = 1 if $what->{NV};
170 33 100 66     130 $params->{PV} = 1 if $what->{PV} || $what->{PVN};
171 33 100       76 $params->{SV} = 1 if $what->{SV};
172 33         95 return $params;
173             }
174              
175              
176             sub C_constant_prefix_param {
177 73     73 0 155 "aTHX_ ";
178             }
179              
180             sub C_constant_prefix_param_definition {
181 24     24 0 110 "pTHX_ ";
182             }
183              
184             sub namelen_param_definition {
185 7     7 0 29 'STRLEN ' . $_[0] -> namelen_param;
186             }
187              
188             sub C_constant_other_params_definition {
189 17     17 0 35 my ($self, $params) = @_;
190 17         33 my $body = '';
191 17 100       44 $body .= ", int utf8" if $params->{''};
192 17 100       48 $body .= ", IV *iv_return" if $params->{IV};
193 17 100       47 $body .= ", NV *nv_return" if $params->{NV};
194 17 100       48 $body .= ", const char **pv_return" if $params->{PV};
195 17 100       49 $body .= ", SV **sv_return" if $params->{SV};
196 17         39 $body;
197             }
198              
199             sub C_constant_other_params {
200 10     10 0 24 my ($self, $params) = @_;
201 10         26 my $body = '';
202 10 100       35 $body .= ", utf8" if $params->{''};
203 10 100       32 $body .= ", iv_return" if $params->{IV};
204 10 50       29 $body .= ", nv_return" if $params->{NV};
205 10 100       26 $body .= ", pv_return" if $params->{PV};
206 10 50       25 $body .= ", sv_return" if $params->{SV};
207 10         29 $body;
208             }
209              
210             sub dogfood {
211 7     7 1 27 my ($self, $args, @items) = @_;
212             my ($package, $subname, $default_type, $what, $indent, $breakout) =
213 7         19 @{$args}{qw(package subname default_type what indent breakout)};
  7         27  
214 7         28 my $result = <<"EOT";
215             /* When generated this function returned values for the list of names given
216             in this section of perl code. Rather than manually editing these functions
217             to add or remove constants, which would result in this comment and section
218             of code becoming inaccurate, we recommend that you edit this section of
219             code, and use it to regenerate a new set of constant functions which you
220             then use to replace the originals.
221              
222             Regenerate these constant functions by feeding this entire source file to
223             perl -x
224              
225             #!$^X -w
226             use ExtUtils::Constant qw (constant_types C_constant XS_constant);
227              
228             EOT
229 7         77 $result .= $self->dump_names ({default_type=>$default_type, what=>$what,
230             indent=>0, declare_types=>1},
231             @items);
232 7         23 $result .= <<'EOT';
233              
234             print constant_types(), "\n"; # macro defs
235             EOT
236 7         36 $package = perl_stringify($package);
237 7         29 $result .=
238             "foreach (C_constant (\"$package\", '$subname', '$default_type', \$types, ";
239             # The form of the indent parameter isn't defined. (Yet)
240 7 50       24 if (defined $indent) {
241 0         0 require Data::Dumper;
242 0         0 $Data::Dumper::Terse=1;
243 0         0 $Data::Dumper::Terse=1; # Not used once. :-)
244 0         0 chomp ($indent = Data::Dumper::Dumper ($indent));
245 0         0 $result .= $indent;
246             } else {
247 7         17 $result .= 'undef';
248             }
249 7         32 $result .= ", $breakout" . ', @names) ) {
250             print $_, "\n"; # C constant subs
251             }
252             print "\n#### XS Section:\n";
253             print XS_constant ("' . $package . '", $types);
254             __END__