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