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