| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package ExtUtils::Constant::XS; | 
| 2 |  |  |  |  |  |  |  | 
| 3 | 1 |  |  | 1 |  | 6 | use strict; | 
|  | 1 |  |  |  |  | 7 |  | 
|  | 1 |  |  |  |  | 27 |  | 
| 4 | 1 |  |  | 1 |  | 4 | use vars qw($VERSION %XS_Constant %XS_TypeSet @ISA @EXPORT_OK $is_perl56); | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 59 |  | 
| 5 | 1 |  |  | 1 |  | 4 | use Carp; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 42 |  | 
| 6 | 1 |  |  | 1 |  | 5 | use ExtUtils::Constant::Utils 'perl_stringify'; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 1086 |  | 
| 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.03'; | 
| 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 | 7 |  |  | 7 | 1 | 28 | my $start = 1; | 
| 72 | 7 |  |  |  |  | 22 | my @lines; | 
| 73 | 7 |  |  |  |  | 43 | push @lines, "#define PERL_constant_NOTFOUND\t$start\n"; $start++; | 
|  | 7 |  |  |  |  | 24 |  | 
| 74 | 7 |  |  |  |  | 26 | push @lines, "#define PERL_constant_NOTDEF\t$start\n"; $start++; | 
|  | 7 |  |  |  |  | 17 |  | 
| 75 | 7 |  |  |  |  | 143 | foreach (sort keys %XS_Constant) { | 
| 76 | 70 | 100 |  |  |  | 188 | next if $_ eq ''; | 
| 77 | 63 |  |  |  |  | 188 | push @lines, "#define PERL_constant_IS$_\t$start\n"; $start++; | 
|  | 63 |  |  |  |  | 129 |  | 
| 78 |  |  |  |  |  |  | } | 
| 79 | 7 |  |  |  |  | 41 | 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 |  |  |  |  |  |  | EOT | 
| 91 |  |  |  |  |  |  |  | 
| 92 | 7 |  |  |  |  | 83 | return join '', @lines; | 
| 93 |  |  |  |  |  |  | } | 
| 94 |  |  |  |  |  |  |  | 
| 95 |  |  |  |  |  |  | sub valid_type { | 
| 96 | 165 |  |  | 165 | 0 | 373 | my ($self, $type) = @_; | 
| 97 | 165 |  |  |  |  | 1257 | return exists $XS_TypeSet{$type}; | 
| 98 |  |  |  |  |  |  | } | 
| 99 |  |  |  |  |  |  |  | 
| 100 |  |  |  |  |  |  | # This might actually be a return statement | 
| 101 |  |  |  |  |  |  | sub assignment_clause_for_type { | 
| 102 | 74 |  |  | 74 | 0 | 162 | my $self = shift; | 
| 103 | 74 |  |  |  |  | 138 | my $args = shift; | 
| 104 | 74 |  |  |  |  | 165 | my $type = $args->{type}; | 
| 105 | 74 |  |  |  |  | 176 | my $typeset = $XS_TypeSet{$type}; | 
| 106 | 74 | 100 |  |  |  | 309 | if (ref $typeset) { | 
|  |  | 100 |  |  |  |  |  | 
| 107 | 1 | 50 |  |  |  | 6 | die "Type $type is aggregate, but only single value given" | 
| 108 |  |  |  |  |  |  | if @_ == 1; | 
| 109 | 1 |  |  |  |  | 7 | return map {"$typeset->[$_]$_[$_];"} 0 .. $#$typeset; | 
|  | 2 |  |  |  |  | 16 |  | 
| 110 |  |  |  |  |  |  | } elsif (defined $typeset) { | 
| 111 | 70 | 50 |  |  |  | 210 | confess "Aggregate value given for type $type" | 
| 112 |  |  |  |  |  |  | if @_ > 1; | 
| 113 | 70 |  |  |  |  | 340 | return "$typeset$_[0];"; | 
| 114 |  |  |  |  |  |  | } | 
| 115 | 3 |  |  |  |  | 14 | return (); | 
| 116 |  |  |  |  |  |  | } | 
| 117 |  |  |  |  |  |  |  | 
| 118 |  |  |  |  |  |  | sub return_statement_for_type { | 
| 119 | 74 |  |  | 74 | 0 | 199 | my ($self, $type) = @_; | 
| 120 |  |  |  |  |  |  | # In the future may pass in an options hash | 
| 121 | 74 | 50 |  |  |  | 211 | $type = $type->{type} if ref $type; | 
| 122 | 74 |  |  |  |  | 269 | "return PERL_constant_IS$type;"; | 
| 123 |  |  |  |  |  |  | } | 
| 124 |  |  |  |  |  |  |  | 
| 125 |  |  |  |  |  |  | sub return_statement_for_notdef { | 
| 126 |  |  |  |  |  |  | # my ($self) = @_; | 
| 127 | 56 |  |  | 56 | 0 | 166 | "return PERL_constant_NOTDEF;"; | 
| 128 |  |  |  |  |  |  | } | 
| 129 |  |  |  |  |  |  |  | 
| 130 |  |  |  |  |  |  | sub return_statement_for_notfound { | 
| 131 |  |  |  |  |  |  | # my ($self) = @_; | 
| 132 | 17 |  |  | 17 | 0 | 62 | "return PERL_constant_NOTFOUND;"; | 
| 133 |  |  |  |  |  |  | } | 
| 134 |  |  |  |  |  |  |  | 
| 135 |  |  |  |  |  |  | sub default_type { | 
| 136 | 1 |  |  | 1 | 1 | 8 | 'IV'; | 
| 137 |  |  |  |  |  |  | } | 
| 138 |  |  |  |  |  |  |  | 
| 139 |  |  |  |  |  |  | sub macro_from_name { | 
| 140 | 115 |  |  | 115 | 0 | 228 | my ($self, $item) = @_; | 
| 141 | 115 |  |  |  |  | 222 | my $macro = $item->{name}; | 
| 142 | 115 | 50 |  |  |  | 288 | $macro = $item->{value} unless defined $macro; | 
| 143 | 115 |  |  |  |  | 289 | $macro; | 
| 144 |  |  |  |  |  |  | } | 
| 145 |  |  |  |  |  |  |  | 
| 146 |  |  |  |  |  |  | sub macro_from_item { | 
| 147 | 143 |  |  | 143 | 0 | 315 | my ($self, $item) = @_; | 
| 148 | 143 |  |  |  |  | 286 | my $macro = $item->{macro}; | 
| 149 | 143 | 100 |  |  |  | 446 | $macro = $self->macro_from_name($item) unless defined $macro; | 
| 150 | 143 |  |  |  |  | 419 | $macro; | 
| 151 |  |  |  |  |  |  | } | 
| 152 |  |  |  |  |  |  |  | 
| 153 |  |  |  |  |  |  | # Keep to the traditional perl source macro | 
| 154 |  |  |  |  |  |  | sub memEQ { | 
| 155 | 18 |  |  | 18 | 0 | 58 | "memEQ"; | 
| 156 |  |  |  |  |  |  | } | 
| 157 |  |  |  |  |  |  |  | 
| 158 |  |  |  |  |  |  | sub params { | 
| 159 | 33 |  |  | 33 | 1 | 100 | my ($self, $what) = @_; | 
| 160 | 33 |  |  |  |  | 175 | foreach (sort keys %$what) { | 
| 161 | 74 | 50 |  |  |  | 258 | warn "ExtUtils::Constant doesn't know how to handle values of type $_" unless defined $XS_Constant{$_}; | 
| 162 |  |  |  |  |  |  | } | 
| 163 | 33 |  |  |  |  | 96 | my $params = {}; | 
| 164 | 33 | 100 |  |  |  | 131 | $params->{''} = 1 if $what->{''}; | 
| 165 | 33 | 100 | 66 |  |  | 189 | $params->{IV} = 1 if $what->{IV} || $what->{UV} || $what->{PVN}; | 
|  |  |  | 66 |  |  |  |  | 
| 166 | 33 | 100 |  |  |  | 108 | $params->{NV} = 1 if $what->{NV}; | 
| 167 | 33 | 100 | 66 |  |  | 173 | $params->{PV} = 1 if $what->{PV} || $what->{PVN}; | 
| 168 | 33 | 100 |  |  |  | 117 | $params->{SV} = 1 if $what->{SV}; | 
| 169 | 33 |  |  |  |  | 116 | return $params; | 
| 170 |  |  |  |  |  |  | } | 
| 171 |  |  |  |  |  |  |  | 
| 172 |  |  |  |  |  |  |  | 
| 173 |  |  |  |  |  |  | sub C_constant_prefix_param { | 
| 174 | 19 |  |  | 19 | 0 | 67 | "aTHX_ "; | 
| 175 |  |  |  |  |  |  | } | 
| 176 |  |  |  |  |  |  |  | 
| 177 |  |  |  |  |  |  | sub C_constant_prefix_param_defintion { | 
| 178 | 18 |  |  | 18 | 0 | 89 | "pTHX_ "; | 
| 179 |  |  |  |  |  |  | } | 
| 180 |  |  |  |  |  |  |  | 
| 181 |  |  |  |  |  |  | sub namelen_param_definition { | 
| 182 | 7 |  |  | 7 | 0 | 88 | 'STRLEN ' . $_[0] -> namelen_param; | 
| 183 |  |  |  |  |  |  | } | 
| 184 |  |  |  |  |  |  |  | 
| 185 |  |  |  |  |  |  | sub C_constant_other_params_defintion { | 
| 186 | 17 |  |  | 17 | 0 | 60 | my ($self, $params) = @_; | 
| 187 | 17 |  |  |  |  | 52 | my $body = ''; | 
| 188 | 17 | 100 |  |  |  | 66 | $body .= ", int utf8" if $params->{''}; | 
| 189 | 17 | 100 |  |  |  | 92 | $body .= ", IV *iv_return" if $params->{IV}; | 
| 190 | 17 | 100 |  |  |  | 116 | $body .= ", NV *nv_return" if $params->{NV}; | 
| 191 | 17 | 100 |  |  |  | 74 | $body .= ", const char **pv_return" if $params->{PV}; | 
| 192 | 17 | 100 |  |  |  | 57 | $body .= ", SV **sv_return" if $params->{SV}; | 
| 193 | 17 |  |  |  |  | 69 | $body; | 
| 194 |  |  |  |  |  |  | } | 
| 195 |  |  |  |  |  |  |  | 
| 196 |  |  |  |  |  |  | sub C_constant_other_params { | 
| 197 | 10 |  |  | 10 | 0 | 32 | my ($self, $params) = @_; | 
| 198 | 10 |  |  |  |  | 33 | my $body = ''; | 
| 199 | 10 | 100 |  |  |  | 42 | $body .= ", utf8" if $params->{''}; | 
| 200 | 10 | 100 |  |  |  | 35 | $body .= ", iv_return" if $params->{IV}; | 
| 201 | 10 | 50 |  |  |  | 34 | $body .= ", nv_return" if $params->{NV}; | 
| 202 | 10 | 100 |  |  |  | 39 | $body .= ", pv_return" if $params->{PV}; | 
| 203 | 10 | 50 |  |  |  | 41 | $body .= ", sv_return" if $params->{SV}; | 
| 204 | 10 |  |  |  |  | 34 | $body; | 
| 205 |  |  |  |  |  |  | } | 
| 206 |  |  |  |  |  |  |  | 
| 207 |  |  |  |  |  |  | sub dogfood { | 
| 208 | 7 |  |  | 7 | 1 | 39 | my ($self, $args, @items) = @_; | 
| 209 |  |  |  |  |  |  | my ($package, $subname, $default_type, $what, $indent, $breakout) = | 
| 210 | 7 |  |  |  |  | 29 | @{$args}{qw(package subname default_type what indent breakout)}; | 
|  | 7 |  |  |  |  | 40 |  | 
| 211 | 7 |  |  |  |  | 41 | my $result = <<"EOT"; | 
| 212 |  |  |  |  |  |  | /* When generated this function returned values for the list of names given | 
| 213 |  |  |  |  |  |  | in this section of perl code.  Rather than manually editing these functions | 
| 214 |  |  |  |  |  |  | to add or remove constants, which would result in this comment and section | 
| 215 |  |  |  |  |  |  | of code becoming inaccurate, we recommend that you edit this section of | 
| 216 |  |  |  |  |  |  | code, and use it to regenerate a new set of constant functions which you | 
| 217 |  |  |  |  |  |  | then use to replace the originals. | 
| 218 |  |  |  |  |  |  |  | 
| 219 |  |  |  |  |  |  | Regenerate these constant functions by feeding this entire source file to | 
| 220 |  |  |  |  |  |  | perl -x | 
| 221 |  |  |  |  |  |  |  | 
| 222 |  |  |  |  |  |  | #!$^X -w | 
| 223 |  |  |  |  |  |  | use ExtUtils::Constant qw (constant_types C_constant XS_constant); | 
| 224 |  |  |  |  |  |  |  | 
| 225 |  |  |  |  |  |  | EOT | 
| 226 | 7 |  |  |  |  | 102 | $result .= $self->dump_names ({default_type=>$default_type, what=>$what, | 
| 227 |  |  |  |  |  |  | indent=>0, declare_types=>1}, | 
| 228 |  |  |  |  |  |  | @items); | 
| 229 | 7 |  |  |  |  | 38 | $result .= <<'EOT'; | 
| 230 |  |  |  |  |  |  |  | 
| 231 |  |  |  |  |  |  | print constant_types(), "\n"; # macro defs | 
| 232 |  |  |  |  |  |  | EOT | 
| 233 | 7 |  |  |  |  | 58 | $package = perl_stringify($package); | 
| 234 | 7 |  |  |  |  | 39 | $result .= | 
| 235 |  |  |  |  |  |  | "foreach (C_constant (\"$package\", '$subname', '$default_type', \$types, "; | 
| 236 |  |  |  |  |  |  | # The form of the indent parameter isn't defined. (Yet) | 
| 237 | 7 | 50 |  |  |  | 32 | if (defined $indent) { | 
| 238 | 0 |  |  |  |  | 0 | require Data::Dumper; | 
| 239 | 0 |  |  |  |  | 0 | $Data::Dumper::Terse=1; | 
| 240 | 0 |  |  |  |  | 0 | $Data::Dumper::Terse=1; # Not used once. :-) | 
| 241 | 0 |  |  |  |  | 0 | chomp ($indent = Data::Dumper::Dumper ($indent)); | 
| 242 | 0 |  |  |  |  | 0 | $result .= $indent; | 
| 243 |  |  |  |  |  |  | } else { | 
| 244 | 7 |  |  |  |  | 20 | $result .= 'undef'; | 
| 245 |  |  |  |  |  |  | } | 
| 246 | 7 |  |  |  |  | 32 | $result .= ", $breakout" . ', @names) ) { | 
| 247 |  |  |  |  |  |  | print $_, "\n"; # C constant subs | 
| 248 |  |  |  |  |  |  | } | 
| 249 |  |  |  |  |  |  | print "\n#### XS Section:\n"; | 
| 250 |  |  |  |  |  |  | print XS_constant ("' . $package . '", $types); | 
| 251 |  |  |  |  |  |  | __END__ |