1*0Sstevel@tonic-gatepackage ExtUtils::Constant; 2*0Sstevel@tonic-gateuse vars qw (@ISA $VERSION %XS_Constant %XS_TypeSet @EXPORT_OK %EXPORT_TAGS); 3*0Sstevel@tonic-gate$VERSION = '0.14'; 4*0Sstevel@tonic-gate 5*0Sstevel@tonic-gate=head1 NAME 6*0Sstevel@tonic-gate 7*0Sstevel@tonic-gateExtUtils::Constant - generate XS code to import C header constants 8*0Sstevel@tonic-gate 9*0Sstevel@tonic-gate=head1 SYNOPSIS 10*0Sstevel@tonic-gate 11*0Sstevel@tonic-gate use ExtUtils::Constant qw (WriteConstants); 12*0Sstevel@tonic-gate WriteConstants( 13*0Sstevel@tonic-gate NAME => 'Foo', 14*0Sstevel@tonic-gate NAMES => [qw(FOO BAR BAZ)], 15*0Sstevel@tonic-gate ); 16*0Sstevel@tonic-gate # Generates wrapper code to make the values of the constants FOO BAR BAZ 17*0Sstevel@tonic-gate # available to perl 18*0Sstevel@tonic-gate 19*0Sstevel@tonic-gate=head1 DESCRIPTION 20*0Sstevel@tonic-gate 21*0Sstevel@tonic-gateExtUtils::Constant facilitates generating C and XS wrapper code to allow 22*0Sstevel@tonic-gateperl modules to AUTOLOAD constants defined in C library header files. 23*0Sstevel@tonic-gateIt is principally used by the C<h2xs> utility, on which this code is based. 24*0Sstevel@tonic-gateIt doesn't contain the routines to scan header files to extract these 25*0Sstevel@tonic-gateconstants. 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate=head1 USAGE 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gateGenerally one only needs to call the C<WriteConstants> function, and then 30*0Sstevel@tonic-gate 31*0Sstevel@tonic-gate #include "const-c.inc" 32*0Sstevel@tonic-gate 33*0Sstevel@tonic-gatein the C section of C<Foo.xs> 34*0Sstevel@tonic-gate 35*0Sstevel@tonic-gate INCLUDE const-xs.inc 36*0Sstevel@tonic-gate 37*0Sstevel@tonic-gatein the XS section of C<Foo.xs>. 38*0Sstevel@tonic-gate 39*0Sstevel@tonic-gateFor greater flexibility use C<constant_types()>, C<C_constant> and 40*0Sstevel@tonic-gateC<XS_constant>, with which C<WriteConstants> is implemented. 41*0Sstevel@tonic-gate 42*0Sstevel@tonic-gateCurrently this module understands the following types. h2xs may only know 43*0Sstevel@tonic-gatea subset. The sizes of the numeric types are chosen by the C<Configure> 44*0Sstevel@tonic-gatescript at compile time. 45*0Sstevel@tonic-gate 46*0Sstevel@tonic-gate=over 4 47*0Sstevel@tonic-gate 48*0Sstevel@tonic-gate=item IV 49*0Sstevel@tonic-gate 50*0Sstevel@tonic-gatesigned integer, at least 32 bits. 51*0Sstevel@tonic-gate 52*0Sstevel@tonic-gate=item UV 53*0Sstevel@tonic-gate 54*0Sstevel@tonic-gateunsigned integer, the same size as I<IV> 55*0Sstevel@tonic-gate 56*0Sstevel@tonic-gate=item NV 57*0Sstevel@tonic-gate 58*0Sstevel@tonic-gatefloating point type, probably C<double>, possibly C<long double> 59*0Sstevel@tonic-gate 60*0Sstevel@tonic-gate=item PV 61*0Sstevel@tonic-gate 62*0Sstevel@tonic-gateNUL terminated string, length will be determined with C<strlen> 63*0Sstevel@tonic-gate 64*0Sstevel@tonic-gate=item PVN 65*0Sstevel@tonic-gate 66*0Sstevel@tonic-gateA fixed length thing, given as a [pointer, length] pair. If you know the 67*0Sstevel@tonic-gatelength of a string at compile time you may use this instead of I<PV> 68*0Sstevel@tonic-gate 69*0Sstevel@tonic-gate=item SV 70*0Sstevel@tonic-gate 71*0Sstevel@tonic-gateA B<mortal> SV. 72*0Sstevel@tonic-gate 73*0Sstevel@tonic-gate=item YES 74*0Sstevel@tonic-gate 75*0Sstevel@tonic-gateTruth. (C<PL_sv_yes>) The value is not needed (and ignored). 76*0Sstevel@tonic-gate 77*0Sstevel@tonic-gate=item NO 78*0Sstevel@tonic-gate 79*0Sstevel@tonic-gateDefined Falsehood. (C<PL_sv_no>) The value is not needed (and ignored). 80*0Sstevel@tonic-gate 81*0Sstevel@tonic-gate=item UNDEF 82*0Sstevel@tonic-gate 83*0Sstevel@tonic-gateC<undef>. The value of the macro is not needed. 84*0Sstevel@tonic-gate 85*0Sstevel@tonic-gate=back 86*0Sstevel@tonic-gate 87*0Sstevel@tonic-gate=head1 FUNCTIONS 88*0Sstevel@tonic-gate 89*0Sstevel@tonic-gate=over 4 90*0Sstevel@tonic-gate 91*0Sstevel@tonic-gate=cut 92*0Sstevel@tonic-gate 93*0Sstevel@tonic-gateif ($] >= 5.006) { 94*0Sstevel@tonic-gate eval "use warnings; 1" or die $@; 95*0Sstevel@tonic-gate} 96*0Sstevel@tonic-gateuse strict; 97*0Sstevel@tonic-gateuse vars '$is_perl56'; 98*0Sstevel@tonic-gateuse Carp; 99*0Sstevel@tonic-gate 100*0Sstevel@tonic-gate$is_perl56 = ($] < 5.007 && $] > 5.005_50); 101*0Sstevel@tonic-gate 102*0Sstevel@tonic-gateuse Exporter; 103*0Sstevel@tonic-gateuse Text::Wrap; 104*0Sstevel@tonic-gate$Text::Wrap::huge = 'overflow'; 105*0Sstevel@tonic-gate$Text::Wrap::columns = 80; 106*0Sstevel@tonic-gate 107*0Sstevel@tonic-gate@ISA = 'Exporter'; 108*0Sstevel@tonic-gate 109*0Sstevel@tonic-gate%EXPORT_TAGS = ( 'all' => [ qw( 110*0Sstevel@tonic-gate XS_constant constant_types return_clause memEQ_clause C_stringify 111*0Sstevel@tonic-gate C_constant autoload WriteConstants WriteMakefileSnippet 112*0Sstevel@tonic-gate) ] ); 113*0Sstevel@tonic-gate 114*0Sstevel@tonic-gate@EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } ); 115*0Sstevel@tonic-gate 116*0Sstevel@tonic-gate# '' is used as a flag to indicate non-ascii macro names, and hence the need 117*0Sstevel@tonic-gate# to pass in the utf8 on/off flag. 118*0Sstevel@tonic-gate%XS_Constant = ( 119*0Sstevel@tonic-gate '' => '', 120*0Sstevel@tonic-gate IV => 'PUSHi(iv)', 121*0Sstevel@tonic-gate UV => 'PUSHu((UV)iv)', 122*0Sstevel@tonic-gate NV => 'PUSHn(nv)', 123*0Sstevel@tonic-gate PV => 'PUSHp(pv, strlen(pv))', 124*0Sstevel@tonic-gate PVN => 'PUSHp(pv, iv)', 125*0Sstevel@tonic-gate SV => 'PUSHs(sv)', 126*0Sstevel@tonic-gate YES => 'PUSHs(&PL_sv_yes)', 127*0Sstevel@tonic-gate NO => 'PUSHs(&PL_sv_no)', 128*0Sstevel@tonic-gate UNDEF => '', # implicit undef 129*0Sstevel@tonic-gate); 130*0Sstevel@tonic-gate 131*0Sstevel@tonic-gate%XS_TypeSet = ( 132*0Sstevel@tonic-gate IV => '*iv_return =', 133*0Sstevel@tonic-gate UV => '*iv_return = (IV)', 134*0Sstevel@tonic-gate NV => '*nv_return =', 135*0Sstevel@tonic-gate PV => '*pv_return =', 136*0Sstevel@tonic-gate PVN => ['*pv_return =', '*iv_return = (IV)'], 137*0Sstevel@tonic-gate SV => '*sv_return = ', 138*0Sstevel@tonic-gate YES => undef, 139*0Sstevel@tonic-gate NO => undef, 140*0Sstevel@tonic-gate UNDEF => undef, 141*0Sstevel@tonic-gate); 142*0Sstevel@tonic-gate 143*0Sstevel@tonic-gate 144*0Sstevel@tonic-gate=item C_stringify NAME 145*0Sstevel@tonic-gate 146*0Sstevel@tonic-gateA function which returns a 7 bit ASCII correctly \ escaped version of the 147*0Sstevel@tonic-gatestring passed suitable for C's "" or ''. It will die if passed Unicode 148*0Sstevel@tonic-gatecharacters. 149*0Sstevel@tonic-gate 150*0Sstevel@tonic-gate=cut 151*0Sstevel@tonic-gate 152*0Sstevel@tonic-gate# Hopefully make a happy C identifier. 153*0Sstevel@tonic-gatesub C_stringify { 154*0Sstevel@tonic-gate local $_ = shift; 155*0Sstevel@tonic-gate return unless defined $_; 156*0Sstevel@tonic-gate # grr 5.6.1 157*0Sstevel@tonic-gate confess "Wide character in '$_' intended as a C identifier" 158*0Sstevel@tonic-gate if tr/\0-\377// != length; 159*0Sstevel@tonic-gate # grr 5.6.1 moreso because its regexps will break on data that happens to 160*0Sstevel@tonic-gate # be utf8, which includes my 8 bit test cases. 161*0Sstevel@tonic-gate $_ = pack 'C*', unpack 'U*', $_ . pack 'U*' if $is_perl56; 162*0Sstevel@tonic-gate s/\\/\\\\/g; 163*0Sstevel@tonic-gate s/([\"\'])/\\$1/g; # Grr. fix perl mode. 164*0Sstevel@tonic-gate s/\n/\\n/g; # Ensure newlines don't end up in octal 165*0Sstevel@tonic-gate s/\r/\\r/g; 166*0Sstevel@tonic-gate s/\t/\\t/g; 167*0Sstevel@tonic-gate s/\f/\\f/g; 168*0Sstevel@tonic-gate s/\a/\\a/g; 169*0Sstevel@tonic-gate s/([^\0-\177])/sprintf "\\%03o", ord $1/ge; 170*0Sstevel@tonic-gate unless ($] < 5.006) { 171*0Sstevel@tonic-gate # This will elicit a warning on 5.005_03 about [: :] being reserved unless 172*0Sstevel@tonic-gate # I cheat 173*0Sstevel@tonic-gate my $cheat = '([[:^print:]])'; 174*0Sstevel@tonic-gate s/$cheat/sprintf "\\%03o", ord $1/ge; 175*0Sstevel@tonic-gate } else { 176*0Sstevel@tonic-gate require POSIX; 177*0Sstevel@tonic-gate s/([^A-Za-z0-9_])/POSIX::isprint($1) ? $1 : sprintf "\\%03o", ord $1/ge; 178*0Sstevel@tonic-gate } 179*0Sstevel@tonic-gate $_; 180*0Sstevel@tonic-gate} 181*0Sstevel@tonic-gate 182*0Sstevel@tonic-gate=item perl_stringify NAME 183*0Sstevel@tonic-gate 184*0Sstevel@tonic-gateA function which returns a 7 bit ASCII correctly \ escaped version of the 185*0Sstevel@tonic-gatestring passed suitable for a perl "" string. 186*0Sstevel@tonic-gate 187*0Sstevel@tonic-gate=cut 188*0Sstevel@tonic-gate 189*0Sstevel@tonic-gate# Hopefully make a happy perl identifier. 190*0Sstevel@tonic-gatesub perl_stringify { 191*0Sstevel@tonic-gate local $_ = shift; 192*0Sstevel@tonic-gate return unless defined $_; 193*0Sstevel@tonic-gate s/\\/\\\\/g; 194*0Sstevel@tonic-gate s/([\"\'])/\\$1/g; # Grr. fix perl mode. 195*0Sstevel@tonic-gate s/\n/\\n/g; # Ensure newlines don't end up in octal 196*0Sstevel@tonic-gate s/\r/\\r/g; 197*0Sstevel@tonic-gate s/\t/\\t/g; 198*0Sstevel@tonic-gate s/\f/\\f/g; 199*0Sstevel@tonic-gate s/\a/\\a/g; 200*0Sstevel@tonic-gate unless ($] < 5.006) { 201*0Sstevel@tonic-gate if ($] > 5.007) { 202*0Sstevel@tonic-gate s/([^\0-\177])/sprintf "\\x{%X}", ord $1/ge; 203*0Sstevel@tonic-gate } else { 204*0Sstevel@tonic-gate # Grr 5.6.1. And I don't think I can use utf8; to force the regexp 205*0Sstevel@tonic-gate # because 5.005_03 will fail. 206*0Sstevel@tonic-gate # This is grim, but I also can't split on // 207*0Sstevel@tonic-gate my $copy; 208*0Sstevel@tonic-gate foreach my $index (0 .. length ($_) - 1) { 209*0Sstevel@tonic-gate my $char = substr ($_, $index, 1); 210*0Sstevel@tonic-gate $copy .= ($char le "\177") ? $char : sprintf "\\x{%X}", ord $char; 211*0Sstevel@tonic-gate } 212*0Sstevel@tonic-gate $_ = $copy; 213*0Sstevel@tonic-gate } 214*0Sstevel@tonic-gate # This will elicit a warning on 5.005_03 about [: :] being reserved unless 215*0Sstevel@tonic-gate # I cheat 216*0Sstevel@tonic-gate my $cheat = '([[:^print:]])'; 217*0Sstevel@tonic-gate s/$cheat/sprintf "\\%03o", ord $1/ge; 218*0Sstevel@tonic-gate } else { 219*0Sstevel@tonic-gate # Turns out "\x{}" notation only arrived with 5.6 220*0Sstevel@tonic-gate s/([^\0-\177])/sprintf "\\x%02X", ord $1/ge; 221*0Sstevel@tonic-gate require POSIX; 222*0Sstevel@tonic-gate s/([^A-Za-z0-9_])/POSIX::isprint($1) ? $1 : sprintf "\\%03o", ord $1/ge; 223*0Sstevel@tonic-gate } 224*0Sstevel@tonic-gate $_; 225*0Sstevel@tonic-gate} 226*0Sstevel@tonic-gate 227*0Sstevel@tonic-gate=item constant_types 228*0Sstevel@tonic-gate 229*0Sstevel@tonic-gateA function returning a single scalar with C<#define> definitions for the 230*0Sstevel@tonic-gateconstants used internally between the generated C and XS functions. 231*0Sstevel@tonic-gate 232*0Sstevel@tonic-gate=cut 233*0Sstevel@tonic-gate 234*0Sstevel@tonic-gatesub constant_types () { 235*0Sstevel@tonic-gate my $start = 1; 236*0Sstevel@tonic-gate my @lines; 237*0Sstevel@tonic-gate push @lines, "#define PERL_constant_NOTFOUND\t$start\n"; $start++; 238*0Sstevel@tonic-gate push @lines, "#define PERL_constant_NOTDEF\t$start\n"; $start++; 239*0Sstevel@tonic-gate foreach (sort keys %XS_Constant) { 240*0Sstevel@tonic-gate next if $_ eq ''; 241*0Sstevel@tonic-gate push @lines, "#define PERL_constant_IS$_\t$start\n"; $start++; 242*0Sstevel@tonic-gate } 243*0Sstevel@tonic-gate push @lines, << 'EOT'; 244*0Sstevel@tonic-gate 245*0Sstevel@tonic-gate#ifndef NVTYPE 246*0Sstevel@tonic-gatetypedef double NV; /* 5.6 and later define NVTYPE, and typedef NV to it. */ 247*0Sstevel@tonic-gate#endif 248*0Sstevel@tonic-gate#ifndef aTHX_ 249*0Sstevel@tonic-gate#define aTHX_ /* 5.6 or later define this for threading support. */ 250*0Sstevel@tonic-gate#endif 251*0Sstevel@tonic-gate#ifndef pTHX_ 252*0Sstevel@tonic-gate#define pTHX_ /* 5.6 or later define this for threading support. */ 253*0Sstevel@tonic-gate#endif 254*0Sstevel@tonic-gateEOT 255*0Sstevel@tonic-gate 256*0Sstevel@tonic-gate return join '', @lines; 257*0Sstevel@tonic-gate} 258*0Sstevel@tonic-gate 259*0Sstevel@tonic-gate=item memEQ_clause NAME, CHECKED_AT, INDENT 260*0Sstevel@tonic-gate 261*0Sstevel@tonic-gateA function to return a suitable C C<if> statement to check whether I<NAME> 262*0Sstevel@tonic-gateis equal to the C variable C<name>. If I<CHECKED_AT> is defined, then it 263*0Sstevel@tonic-gateis used to avoid C<memEQ> for short names, or to generate a comment to 264*0Sstevel@tonic-gatehighlight the position of the character in the C<switch> statement. 265*0Sstevel@tonic-gate 266*0Sstevel@tonic-gateIf I<CHECKED_AT> is a reference to a scalar, then instead it gives 267*0Sstevel@tonic-gatethe characters pre-checked at the beginning, (and the number of chars by 268*0Sstevel@tonic-gatewhich the C variable name has been advanced. These need to be chopped from 269*0Sstevel@tonic-gatethe front of I<NAME>). 270*0Sstevel@tonic-gate 271*0Sstevel@tonic-gate=cut 272*0Sstevel@tonic-gate 273*0Sstevel@tonic-gatesub memEQ_clause { 274*0Sstevel@tonic-gate# if (memEQ(name, "thingy", 6)) { 275*0Sstevel@tonic-gate # Which could actually be a character comparison or even "" 276*0Sstevel@tonic-gate my ($name, $checked_at, $indent) = @_; 277*0Sstevel@tonic-gate $indent = ' ' x ($indent || 4); 278*0Sstevel@tonic-gate my $front_chop; 279*0Sstevel@tonic-gate if (ref $checked_at) { 280*0Sstevel@tonic-gate # regexp won't work on 5.6.1 without use utf8; in turn that won't work 281*0Sstevel@tonic-gate # on 5.005_03. 282*0Sstevel@tonic-gate substr ($name, 0, length $$checked_at,) = ''; 283*0Sstevel@tonic-gate $front_chop = C_stringify ($$checked_at); 284*0Sstevel@tonic-gate undef $checked_at; 285*0Sstevel@tonic-gate } 286*0Sstevel@tonic-gate my $len = length $name; 287*0Sstevel@tonic-gate 288*0Sstevel@tonic-gate if ($len < 2) { 289*0Sstevel@tonic-gate return $indent . "{\n" if (defined $checked_at and $checked_at == 0); 290*0Sstevel@tonic-gate # We didn't switch, drop through to the code for the 2 character string 291*0Sstevel@tonic-gate $checked_at = 1; 292*0Sstevel@tonic-gate } 293*0Sstevel@tonic-gate if ($len < 3 and defined $checked_at) { 294*0Sstevel@tonic-gate my $check; 295*0Sstevel@tonic-gate if ($checked_at == 1) { 296*0Sstevel@tonic-gate $check = 0; 297*0Sstevel@tonic-gate } elsif ($checked_at == 0) { 298*0Sstevel@tonic-gate $check = 1; 299*0Sstevel@tonic-gate } 300*0Sstevel@tonic-gate if (defined $check) { 301*0Sstevel@tonic-gate my $char = C_stringify (substr $name, $check, 1); 302*0Sstevel@tonic-gate return $indent . "if (name[$check] == '$char') {\n"; 303*0Sstevel@tonic-gate } 304*0Sstevel@tonic-gate } 305*0Sstevel@tonic-gate if (($len == 2 and !defined $checked_at) 306*0Sstevel@tonic-gate or ($len == 3 and defined ($checked_at) and $checked_at == 2)) { 307*0Sstevel@tonic-gate my $char1 = C_stringify (substr $name, 0, 1); 308*0Sstevel@tonic-gate my $char2 = C_stringify (substr $name, 1, 1); 309*0Sstevel@tonic-gate return $indent . "if (name[0] == '$char1' && name[1] == '$char2') {\n"; 310*0Sstevel@tonic-gate } 311*0Sstevel@tonic-gate if (($len == 3 and defined ($checked_at) and $checked_at == 1)) { 312*0Sstevel@tonic-gate my $char1 = C_stringify (substr $name, 0, 1); 313*0Sstevel@tonic-gate my $char2 = C_stringify (substr $name, 2, 1); 314*0Sstevel@tonic-gate return $indent . "if (name[0] == '$char1' && name[2] == '$char2') {\n"; 315*0Sstevel@tonic-gate } 316*0Sstevel@tonic-gate 317*0Sstevel@tonic-gate my $pointer = '^'; 318*0Sstevel@tonic-gate my $have_checked_last = defined ($checked_at) && $len == $checked_at + 1; 319*0Sstevel@tonic-gate if ($have_checked_last) { 320*0Sstevel@tonic-gate # Checked at the last character, so no need to memEQ it. 321*0Sstevel@tonic-gate $pointer = C_stringify (chop $name); 322*0Sstevel@tonic-gate $len--; 323*0Sstevel@tonic-gate } 324*0Sstevel@tonic-gate 325*0Sstevel@tonic-gate $name = C_stringify ($name); 326*0Sstevel@tonic-gate my $body = $indent . "if (memEQ(name, \"$name\", $len)) {\n"; 327*0Sstevel@tonic-gate # Put a little ^ under the letter we checked at 328*0Sstevel@tonic-gate # Screws up for non printable and non-7 bit stuff, but that's too hard to 329*0Sstevel@tonic-gate # get right. 330*0Sstevel@tonic-gate if (defined $checked_at) { 331*0Sstevel@tonic-gate $body .= $indent . "/* ". (' ' x $checked_at) . $pointer 332*0Sstevel@tonic-gate . (' ' x ($len - $checked_at + length $len)) . " */\n"; 333*0Sstevel@tonic-gate } elsif (defined $front_chop) { 334*0Sstevel@tonic-gate $body .= $indent . "/* $front_chop" 335*0Sstevel@tonic-gate . (' ' x ($len + 1 + length $len)) . " */\n"; 336*0Sstevel@tonic-gate } 337*0Sstevel@tonic-gate return $body; 338*0Sstevel@tonic-gate} 339*0Sstevel@tonic-gate 340*0Sstevel@tonic-gate=item assign INDENT, TYPE, PRE, POST, VALUE... 341*0Sstevel@tonic-gate 342*0Sstevel@tonic-gateA function to return a suitable assignment clause. If I<TYPE> is aggregate 343*0Sstevel@tonic-gate(eg I<PVN> expects both pointer and length) then there should be multiple 344*0Sstevel@tonic-gateI<VALUE>s for the components. I<PRE> and I<POST> if defined give snippets 345*0Sstevel@tonic-gateof C code to proceed and follow the assignment. I<PRE> will be at the start 346*0Sstevel@tonic-gateof a block, so variables may be defined in it. 347*0Sstevel@tonic-gate 348*0Sstevel@tonic-gate=cut 349*0Sstevel@tonic-gate 350*0Sstevel@tonic-gate# Hmm. value undef to to NOTDEF? value () to do NOTFOUND? 351*0Sstevel@tonic-gate 352*0Sstevel@tonic-gatesub assign { 353*0Sstevel@tonic-gate my $indent = shift; 354*0Sstevel@tonic-gate my $type = shift; 355*0Sstevel@tonic-gate my $pre = shift; 356*0Sstevel@tonic-gate my $post = shift || ''; 357*0Sstevel@tonic-gate my $clause; 358*0Sstevel@tonic-gate my $close; 359*0Sstevel@tonic-gate if ($pre) { 360*0Sstevel@tonic-gate chomp $pre; 361*0Sstevel@tonic-gate $clause = $indent . "{\n$pre"; 362*0Sstevel@tonic-gate $clause .= ";" unless $pre =~ /;$/; 363*0Sstevel@tonic-gate $clause .= "\n"; 364*0Sstevel@tonic-gate $close = "$indent}\n"; 365*0Sstevel@tonic-gate $indent .= " "; 366*0Sstevel@tonic-gate } 367*0Sstevel@tonic-gate confess "undef \$type" unless defined $type; 368*0Sstevel@tonic-gate confess "Can't generate code for type $type" unless exists $XS_TypeSet{$type}; 369*0Sstevel@tonic-gate my $typeset = $XS_TypeSet{$type}; 370*0Sstevel@tonic-gate if (ref $typeset) { 371*0Sstevel@tonic-gate die "Type $type is aggregate, but only single value given" 372*0Sstevel@tonic-gate if @_ == 1; 373*0Sstevel@tonic-gate foreach (0 .. $#$typeset) { 374*0Sstevel@tonic-gate $clause .= $indent . "$typeset->[$_] $_[$_];\n"; 375*0Sstevel@tonic-gate } 376*0Sstevel@tonic-gate } elsif (defined $typeset) { 377*0Sstevel@tonic-gate die "Aggregate value given for type $type" 378*0Sstevel@tonic-gate if @_ > 1; 379*0Sstevel@tonic-gate $clause .= $indent . "$typeset $_[0];\n"; 380*0Sstevel@tonic-gate } 381*0Sstevel@tonic-gate chomp $post; 382*0Sstevel@tonic-gate if (length $post) { 383*0Sstevel@tonic-gate $clause .= "$post"; 384*0Sstevel@tonic-gate $clause .= ";" unless $post =~ /;$/; 385*0Sstevel@tonic-gate $clause .= "\n"; 386*0Sstevel@tonic-gate } 387*0Sstevel@tonic-gate $clause .= "${indent}return PERL_constant_IS$type;\n"; 388*0Sstevel@tonic-gate $clause .= $close if $close; 389*0Sstevel@tonic-gate return $clause; 390*0Sstevel@tonic-gate} 391*0Sstevel@tonic-gate 392*0Sstevel@tonic-gate=item return_clause 393*0Sstevel@tonic-gate 394*0Sstevel@tonic-gatereturn_clause ITEM, INDENT 395*0Sstevel@tonic-gate 396*0Sstevel@tonic-gateA function to return a suitable C<#ifdef> clause. I<ITEM> is a hashref 397*0Sstevel@tonic-gate(as passed to C<C_constant> and C<match_clause>. I<INDENT> is the number 398*0Sstevel@tonic-gateof spaces to indent, defaulting to 6. 399*0Sstevel@tonic-gate 400*0Sstevel@tonic-gate=cut 401*0Sstevel@tonic-gate 402*0Sstevel@tonic-gatesub return_clause ($$) { 403*0Sstevel@tonic-gate##ifdef thingy 404*0Sstevel@tonic-gate# *iv_return = thingy; 405*0Sstevel@tonic-gate# return PERL_constant_ISIV; 406*0Sstevel@tonic-gate##else 407*0Sstevel@tonic-gate# return PERL_constant_NOTDEF; 408*0Sstevel@tonic-gate##endif 409*0Sstevel@tonic-gate my ($item, $indent) = @_; 410*0Sstevel@tonic-gate 411*0Sstevel@tonic-gate my ($name, $value, $macro, $default, $pre, $post, $def_pre, $def_post, $type) 412*0Sstevel@tonic-gate = @$item{qw (name value macro default pre post def_pre def_post type)}; 413*0Sstevel@tonic-gate $value = $name unless defined $value; 414*0Sstevel@tonic-gate $macro = $name unless defined $macro; 415*0Sstevel@tonic-gate 416*0Sstevel@tonic-gate $macro = $value unless defined $macro; 417*0Sstevel@tonic-gate $indent = ' ' x ($indent || 6); 418*0Sstevel@tonic-gate unless ($type) { 419*0Sstevel@tonic-gate # use Data::Dumper; print STDERR Dumper ($item); 420*0Sstevel@tonic-gate confess "undef \$type"; 421*0Sstevel@tonic-gate } 422*0Sstevel@tonic-gate 423*0Sstevel@tonic-gate my $clause; 424*0Sstevel@tonic-gate 425*0Sstevel@tonic-gate ##ifdef thingy 426*0Sstevel@tonic-gate if (ref $macro) { 427*0Sstevel@tonic-gate $clause = $macro->[0]; 428*0Sstevel@tonic-gate } elsif ($macro ne "1") { 429*0Sstevel@tonic-gate $clause = "#ifdef $macro\n"; 430*0Sstevel@tonic-gate } 431*0Sstevel@tonic-gate 432*0Sstevel@tonic-gate # *iv_return = thingy; 433*0Sstevel@tonic-gate # return PERL_constant_ISIV; 434*0Sstevel@tonic-gate $clause .= assign ($indent, $type, $pre, $post, 435*0Sstevel@tonic-gate ref $value ? @$value : $value); 436*0Sstevel@tonic-gate 437*0Sstevel@tonic-gate if (ref $macro or $macro ne "1") { 438*0Sstevel@tonic-gate ##else 439*0Sstevel@tonic-gate $clause .= "#else\n"; 440*0Sstevel@tonic-gate 441*0Sstevel@tonic-gate # return PERL_constant_NOTDEF; 442*0Sstevel@tonic-gate if (!defined $default) { 443*0Sstevel@tonic-gate $clause .= "${indent}return PERL_constant_NOTDEF;\n"; 444*0Sstevel@tonic-gate } else { 445*0Sstevel@tonic-gate my @default = ref $default ? @$default : $default; 446*0Sstevel@tonic-gate $type = shift @default; 447*0Sstevel@tonic-gate $clause .= assign ($indent, $type, $def_pre, $def_post, @default); 448*0Sstevel@tonic-gate } 449*0Sstevel@tonic-gate 450*0Sstevel@tonic-gate ##endif 451*0Sstevel@tonic-gate if (ref $macro) { 452*0Sstevel@tonic-gate $clause .= $macro->[1]; 453*0Sstevel@tonic-gate } else { 454*0Sstevel@tonic-gate $clause .= "#endif\n"; 455*0Sstevel@tonic-gate } 456*0Sstevel@tonic-gate } 457*0Sstevel@tonic-gate return $clause; 458*0Sstevel@tonic-gate} 459*0Sstevel@tonic-gate 460*0Sstevel@tonic-gate=pod 461*0Sstevel@tonic-gate 462*0Sstevel@tonic-gateXXX document me 463*0Sstevel@tonic-gate 464*0Sstevel@tonic-gate=cut 465*0Sstevel@tonic-gate 466*0Sstevel@tonic-gatesub match_clause { 467*0Sstevel@tonic-gate # $offset defined if we have checked an offset. 468*0Sstevel@tonic-gate my ($item, $offset, $indent) = @_; 469*0Sstevel@tonic-gate $indent = ' ' x ($indent || 4); 470*0Sstevel@tonic-gate my $body = ''; 471*0Sstevel@tonic-gate my ($no, $yes, $either, $name, $inner_indent); 472*0Sstevel@tonic-gate if (ref $item eq 'ARRAY') { 473*0Sstevel@tonic-gate ($yes, $no) = @$item; 474*0Sstevel@tonic-gate $either = $yes || $no; 475*0Sstevel@tonic-gate confess "$item is $either expecting hashref in [0] || [1]" 476*0Sstevel@tonic-gate unless ref $either eq 'HASH'; 477*0Sstevel@tonic-gate $name = $either->{name}; 478*0Sstevel@tonic-gate } else { 479*0Sstevel@tonic-gate confess "$item->{name} has utf8 flag '$item->{utf8}', should be false" 480*0Sstevel@tonic-gate if $item->{utf8}; 481*0Sstevel@tonic-gate $name = $item->{name}; 482*0Sstevel@tonic-gate $inner_indent = $indent; 483*0Sstevel@tonic-gate } 484*0Sstevel@tonic-gate 485*0Sstevel@tonic-gate $body .= memEQ_clause ($name, $offset, length $indent); 486*0Sstevel@tonic-gate if ($yes) { 487*0Sstevel@tonic-gate $body .= $indent . " if (utf8) {\n"; 488*0Sstevel@tonic-gate } elsif ($no) { 489*0Sstevel@tonic-gate $body .= $indent . " if (!utf8) {\n"; 490*0Sstevel@tonic-gate } 491*0Sstevel@tonic-gate if ($either) { 492*0Sstevel@tonic-gate $body .= return_clause ($either, 4 + length $indent); 493*0Sstevel@tonic-gate if ($yes and $no) { 494*0Sstevel@tonic-gate $body .= $indent . " } else {\n"; 495*0Sstevel@tonic-gate $body .= return_clause ($no, 4 + length $indent); 496*0Sstevel@tonic-gate } 497*0Sstevel@tonic-gate $body .= $indent . " }\n"; 498*0Sstevel@tonic-gate } else { 499*0Sstevel@tonic-gate $body .= return_clause ($item, 2 + length $indent); 500*0Sstevel@tonic-gate } 501*0Sstevel@tonic-gate $body .= $indent . "}\n"; 502*0Sstevel@tonic-gate} 503*0Sstevel@tonic-gate 504*0Sstevel@tonic-gate=item switch_clause INDENT, NAMELEN, ITEMHASH, ITEM... 505*0Sstevel@tonic-gate 506*0Sstevel@tonic-gateAn internal function to generate a suitable C<switch> clause, called by 507*0Sstevel@tonic-gateC<C_constant> I<ITEM>s are in the hash ref format as given in the description 508*0Sstevel@tonic-gateof C<C_constant>, and must all have the names of the same length, given by 509*0Sstevel@tonic-gateI<NAMELEN> (This is not checked). I<ITEMHASH> is a reference to a hash, 510*0Sstevel@tonic-gatekeyed by name, values being the hashrefs in the I<ITEM> list. 511*0Sstevel@tonic-gate(No parameters are modified, and there can be keys in the I<ITEMHASH> that 512*0Sstevel@tonic-gateare not in the list of I<ITEM>s without causing problems). 513*0Sstevel@tonic-gate 514*0Sstevel@tonic-gate=cut 515*0Sstevel@tonic-gate 516*0Sstevel@tonic-gatesub switch_clause { 517*0Sstevel@tonic-gate my ($indent, $comment, $namelen, $items, @items) = @_; 518*0Sstevel@tonic-gate $indent = ' ' x ($indent || 2); 519*0Sstevel@tonic-gate 520*0Sstevel@tonic-gate my @names = sort map {$_->{name}} @items; 521*0Sstevel@tonic-gate my $leader = $indent . '/* '; 522*0Sstevel@tonic-gate my $follower = ' ' x length $leader; 523*0Sstevel@tonic-gate my $body = $indent . "/* Names all of length $namelen. */\n"; 524*0Sstevel@tonic-gate if ($comment) { 525*0Sstevel@tonic-gate $body = wrap ($leader, $follower, $comment) . "\n"; 526*0Sstevel@tonic-gate $leader = $follower; 527*0Sstevel@tonic-gate } 528*0Sstevel@tonic-gate my @safe_names = @names; 529*0Sstevel@tonic-gate foreach (@safe_names) { 530*0Sstevel@tonic-gate confess sprintf "Name '$_' is length %d, not $namelen", length 531*0Sstevel@tonic-gate unless length == $namelen; 532*0Sstevel@tonic-gate # Argh. 5.6.1 533*0Sstevel@tonic-gate # next unless tr/A-Za-z0-9_//c; 534*0Sstevel@tonic-gate next if tr/A-Za-z0-9_// == length; 535*0Sstevel@tonic-gate $_ = '"' . perl_stringify ($_) . '"'; 536*0Sstevel@tonic-gate # Ensure that the enclosing C comment doesn't end 537*0Sstevel@tonic-gate # by turning */ into *" . "/ 538*0Sstevel@tonic-gate s!\*\/!\*"."/!gs; 539*0Sstevel@tonic-gate # gcc -Wall doesn't like finding /* inside a comment 540*0Sstevel@tonic-gate s!\/\*!/"."\*!gs; 541*0Sstevel@tonic-gate } 542*0Sstevel@tonic-gate $body .= wrap ($leader, $follower, join (" ", @safe_names) . " */") . "\n"; 543*0Sstevel@tonic-gate # Figure out what to switch on. 544*0Sstevel@tonic-gate # (RMS, Spread of jump table, Position, Hashref) 545*0Sstevel@tonic-gate my @best = (1e38, ~0); 546*0Sstevel@tonic-gate # Prefer the last character over the others. (As it lets us shortern the 547*0Sstevel@tonic-gate # memEQ clause at no cost). 548*0Sstevel@tonic-gate foreach my $i ($namelen - 1, 0 .. ($namelen - 2)) { 549*0Sstevel@tonic-gate my ($min, $max) = (~0, 0); 550*0Sstevel@tonic-gate my %spread; 551*0Sstevel@tonic-gate if ($is_perl56) { 552*0Sstevel@tonic-gate # Need proper Unicode preserving hash keys for bytes in range 128-255 553*0Sstevel@tonic-gate # here too, for some reason. grr 5.6.1 yet again. 554*0Sstevel@tonic-gate tie %spread, 'ExtUtils::Constant::Aaargh56Hash'; 555*0Sstevel@tonic-gate } 556*0Sstevel@tonic-gate foreach (@names) { 557*0Sstevel@tonic-gate my $char = substr $_, $i, 1; 558*0Sstevel@tonic-gate my $ord = ord $char; 559*0Sstevel@tonic-gate confess "char $ord is out of range" if $ord > 255; 560*0Sstevel@tonic-gate $max = $ord if $ord > $max; 561*0Sstevel@tonic-gate $min = $ord if $ord < $min; 562*0Sstevel@tonic-gate push @{$spread{$char}}, $_; 563*0Sstevel@tonic-gate # warn "$_ $char"; 564*0Sstevel@tonic-gate } 565*0Sstevel@tonic-gate # I'm going to pick the character to split on that minimises the root 566*0Sstevel@tonic-gate # mean square of the number of names in each case. Normally this should 567*0Sstevel@tonic-gate # be the one with the most keys, but it may pick a 7 where the 8 has 568*0Sstevel@tonic-gate # one long linear search. I'm not sure if RMS or just sum of squares is 569*0Sstevel@tonic-gate # actually better. 570*0Sstevel@tonic-gate # $max and $min are for the tie-breaker if the root mean squares match. 571*0Sstevel@tonic-gate # Assuming that the compiler may be building a jump table for the 572*0Sstevel@tonic-gate # switch() then try to minimise the size of that jump table. 573*0Sstevel@tonic-gate # Finally use < not <= so that if it still ties the earliest part of 574*0Sstevel@tonic-gate # the string wins. Because if that passes but the memEQ fails, it may 575*0Sstevel@tonic-gate # only need the start of the string to bin the choice. 576*0Sstevel@tonic-gate # I think. But I'm micro-optimising. :-) 577*0Sstevel@tonic-gate # OK. Trump that. Now favour the last character of the string, before the 578*0Sstevel@tonic-gate # rest. 579*0Sstevel@tonic-gate my $ss; 580*0Sstevel@tonic-gate $ss += @$_ * @$_ foreach values %spread; 581*0Sstevel@tonic-gate my $rms = sqrt ($ss / keys %spread); 582*0Sstevel@tonic-gate if ($rms < $best[0] || ($rms == $best[0] && ($max - $min) < $best[1])) { 583*0Sstevel@tonic-gate @best = ($rms, $max - $min, $i, \%spread); 584*0Sstevel@tonic-gate } 585*0Sstevel@tonic-gate } 586*0Sstevel@tonic-gate confess "Internal error. Failed to pick a switch point for @names" 587*0Sstevel@tonic-gate unless defined $best[2]; 588*0Sstevel@tonic-gate # use Data::Dumper; print Dumper (@best); 589*0Sstevel@tonic-gate my ($offset, $best) = @best[2,3]; 590*0Sstevel@tonic-gate $body .= $indent . "/* Offset $offset gives the best switch position. */\n"; 591*0Sstevel@tonic-gate 592*0Sstevel@tonic-gate my $do_front_chop = $offset == 0 && $namelen > 2; 593*0Sstevel@tonic-gate if ($do_front_chop) { 594*0Sstevel@tonic-gate $body .= $indent . "switch (*name++) {\n"; 595*0Sstevel@tonic-gate } else { 596*0Sstevel@tonic-gate $body .= $indent . "switch (name[$offset]) {\n"; 597*0Sstevel@tonic-gate } 598*0Sstevel@tonic-gate foreach my $char (sort keys %$best) { 599*0Sstevel@tonic-gate confess sprintf "'$char' is %d bytes long, not 1", length $char 600*0Sstevel@tonic-gate if length ($char) != 1; 601*0Sstevel@tonic-gate confess sprintf "char %#X is out of range", ord $char if ord ($char) > 255; 602*0Sstevel@tonic-gate $body .= $indent . "case '" . C_stringify ($char) . "':\n"; 603*0Sstevel@tonic-gate foreach my $name (sort @{$best->{$char}}) { 604*0Sstevel@tonic-gate my $thisone = $items->{$name}; 605*0Sstevel@tonic-gate # warn "You are here"; 606*0Sstevel@tonic-gate if ($do_front_chop) { 607*0Sstevel@tonic-gate $body .= match_clause ($thisone, \$char, 2 + length $indent); 608*0Sstevel@tonic-gate } else { 609*0Sstevel@tonic-gate $body .= match_clause ($thisone, $offset, 2 + length $indent); 610*0Sstevel@tonic-gate } 611*0Sstevel@tonic-gate } 612*0Sstevel@tonic-gate $body .= $indent . " break;\n"; 613*0Sstevel@tonic-gate } 614*0Sstevel@tonic-gate $body .= $indent . "}\n"; 615*0Sstevel@tonic-gate return $body; 616*0Sstevel@tonic-gate} 617*0Sstevel@tonic-gate 618*0Sstevel@tonic-gate=item params WHAT 619*0Sstevel@tonic-gate 620*0Sstevel@tonic-gateAn internal function. I<WHAT> should be a hashref of types the constant 621*0Sstevel@tonic-gatefunction will return. I<params> returns a hashref keyed IV NV PV SV to show 622*0Sstevel@tonic-gatewhich combination of pointers will be needed in the C argument list. 623*0Sstevel@tonic-gate 624*0Sstevel@tonic-gate=cut 625*0Sstevel@tonic-gate 626*0Sstevel@tonic-gatesub params { 627*0Sstevel@tonic-gate my $what = shift; 628*0Sstevel@tonic-gate foreach (sort keys %$what) { 629*0Sstevel@tonic-gate warn "ExtUtils::Constant doesn't know how to handle values of type $_" unless defined $XS_Constant{$_}; 630*0Sstevel@tonic-gate } 631*0Sstevel@tonic-gate my $params = {}; 632*0Sstevel@tonic-gate $params->{''} = 1 if $what->{''}; 633*0Sstevel@tonic-gate $params->{IV} = 1 if $what->{IV} || $what->{UV} || $what->{PVN}; 634*0Sstevel@tonic-gate $params->{NV} = 1 if $what->{NV}; 635*0Sstevel@tonic-gate $params->{PV} = 1 if $what->{PV} || $what->{PVN}; 636*0Sstevel@tonic-gate $params->{SV} = 1 if $what->{SV}; 637*0Sstevel@tonic-gate return $params; 638*0Sstevel@tonic-gate} 639*0Sstevel@tonic-gate 640*0Sstevel@tonic-gate=item dump_names 641*0Sstevel@tonic-gate 642*0Sstevel@tonic-gatedump_names DEFAULT_TYPE, TYPES, INDENT, OPTIONS, ITEM... 643*0Sstevel@tonic-gate 644*0Sstevel@tonic-gateAn internal function to generate the embedded perl code that will regenerate 645*0Sstevel@tonic-gatethe constant subroutines. I<DEFAULT_TYPE>, I<TYPES> and I<ITEM>s are the 646*0Sstevel@tonic-gatesame as for C_constant. I<INDENT> is treated as number of spaces to indent 647*0Sstevel@tonic-gateby. I<OPTIONS> is a hashref of options. Currently only C<declare_types> is 648*0Sstevel@tonic-gaterecognised. If the value is true a C<$types> is always declared in the perl 649*0Sstevel@tonic-gatecode generated, if defined and false never declared, and if undefined C<$types> 650*0Sstevel@tonic-gateis only declared if the values in I<TYPES> as passed in cannot be inferred from 651*0Sstevel@tonic-gateI<DEFAULT_TYPES> and the I<ITEM>s. 652*0Sstevel@tonic-gate 653*0Sstevel@tonic-gate=cut 654*0Sstevel@tonic-gate 655*0Sstevel@tonic-gatesub dump_names { 656*0Sstevel@tonic-gate my ($default_type, $what, $indent, $options, @items) = @_; 657*0Sstevel@tonic-gate my $declare_types = $options->{declare_types}; 658*0Sstevel@tonic-gate $indent = ' ' x ($indent || 0); 659*0Sstevel@tonic-gate 660*0Sstevel@tonic-gate my $result; 661*0Sstevel@tonic-gate my (@simple, @complex, %used_types); 662*0Sstevel@tonic-gate foreach (@items) { 663*0Sstevel@tonic-gate my $type; 664*0Sstevel@tonic-gate if (ref $_) { 665*0Sstevel@tonic-gate $type = $_->{type} || $default_type; 666*0Sstevel@tonic-gate if ($_->{utf8}) { 667*0Sstevel@tonic-gate # For simplicity always skip the bytes case, and reconstitute this entry 668*0Sstevel@tonic-gate # from its utf8 twin. 669*0Sstevel@tonic-gate next if $_->{utf8} eq 'no'; 670*0Sstevel@tonic-gate # Copy the hashref, as we don't want to mess with the caller's hashref. 671*0Sstevel@tonic-gate $_ = {%$_}; 672*0Sstevel@tonic-gate unless ($is_perl56) { 673*0Sstevel@tonic-gate utf8::decode ($_->{name}); 674*0Sstevel@tonic-gate } else { 675*0Sstevel@tonic-gate $_->{name} = pack 'U*', unpack 'U0U*', $_->{name}; 676*0Sstevel@tonic-gate } 677*0Sstevel@tonic-gate delete $_->{utf8}; 678*0Sstevel@tonic-gate } 679*0Sstevel@tonic-gate } else { 680*0Sstevel@tonic-gate $_ = {name=>$_}; 681*0Sstevel@tonic-gate $type = $default_type; 682*0Sstevel@tonic-gate } 683*0Sstevel@tonic-gate $used_types{$type}++; 684*0Sstevel@tonic-gate if ($type eq $default_type 685*0Sstevel@tonic-gate # grr 5.6.1 686*0Sstevel@tonic-gate and length $_->{name} == ($_->{name} =~ tr/A-Za-z0-9_//) 687*0Sstevel@tonic-gate and !defined ($_->{macro}) and !defined ($_->{value}) 688*0Sstevel@tonic-gate and !defined ($_->{default}) and !defined ($_->{pre}) 689*0Sstevel@tonic-gate and !defined ($_->{post}) and !defined ($_->{def_pre}) 690*0Sstevel@tonic-gate and !defined ($_->{def_post})) { 691*0Sstevel@tonic-gate # It's the default type, and the name consists only of A-Za-z0-9_ 692*0Sstevel@tonic-gate push @simple, $_->{name}; 693*0Sstevel@tonic-gate } else { 694*0Sstevel@tonic-gate push @complex, $_; 695*0Sstevel@tonic-gate } 696*0Sstevel@tonic-gate } 697*0Sstevel@tonic-gate 698*0Sstevel@tonic-gate if (!defined $declare_types) { 699*0Sstevel@tonic-gate # Do they pass in any types we weren't already using? 700*0Sstevel@tonic-gate foreach (keys %$what) { 701*0Sstevel@tonic-gate next if $used_types{$_}; 702*0Sstevel@tonic-gate $declare_types++; # Found one in $what that wasn't used. 703*0Sstevel@tonic-gate last; # And one is enough to terminate this loop 704*0Sstevel@tonic-gate } 705*0Sstevel@tonic-gate } 706*0Sstevel@tonic-gate if ($declare_types) { 707*0Sstevel@tonic-gate $result = $indent . 'my $types = {map {($_, 1)} qw(' 708*0Sstevel@tonic-gate . join (" ", sort keys %$what) . ")};\n"; 709*0Sstevel@tonic-gate } 710*0Sstevel@tonic-gate $result .= wrap ($indent . "my \@names = (qw(", 711*0Sstevel@tonic-gate $indent . " ", join (" ", sort @simple) . ")"); 712*0Sstevel@tonic-gate if (@complex) { 713*0Sstevel@tonic-gate foreach my $item (sort {$a->{name} cmp $b->{name}} @complex) { 714*0Sstevel@tonic-gate my $name = perl_stringify $item->{name}; 715*0Sstevel@tonic-gate my $line = ",\n$indent {name=>\"$name\""; 716*0Sstevel@tonic-gate $line .= ", type=>\"$item->{type}\"" if defined $item->{type}; 717*0Sstevel@tonic-gate foreach my $thing (qw (macro value default pre post def_pre def_post)) { 718*0Sstevel@tonic-gate my $value = $item->{$thing}; 719*0Sstevel@tonic-gate if (defined $value) { 720*0Sstevel@tonic-gate if (ref $value) { 721*0Sstevel@tonic-gate $line .= ", $thing=>[\"" 722*0Sstevel@tonic-gate . join ('", "', map {perl_stringify $_} @$value) . '"]'; 723*0Sstevel@tonic-gate } else { 724*0Sstevel@tonic-gate $line .= ", $thing=>\"" . perl_stringify($value) . "\""; 725*0Sstevel@tonic-gate } 726*0Sstevel@tonic-gate } 727*0Sstevel@tonic-gate } 728*0Sstevel@tonic-gate $line .= "}"; 729*0Sstevel@tonic-gate # Ensure that the enclosing C comment doesn't end 730*0Sstevel@tonic-gate # by turning */ into *" . "/ 731*0Sstevel@tonic-gate $line =~ s!\*\/!\*" . "/!gs; 732*0Sstevel@tonic-gate # gcc -Wall doesn't like finding /* inside a comment 733*0Sstevel@tonic-gate $line =~ s!\/\*!/" . "\*!gs; 734*0Sstevel@tonic-gate $result .= $line; 735*0Sstevel@tonic-gate } 736*0Sstevel@tonic-gate } 737*0Sstevel@tonic-gate $result .= ");\n"; 738*0Sstevel@tonic-gate 739*0Sstevel@tonic-gate $result; 740*0Sstevel@tonic-gate} 741*0Sstevel@tonic-gate 742*0Sstevel@tonic-gate 743*0Sstevel@tonic-gate=item dogfood 744*0Sstevel@tonic-gate 745*0Sstevel@tonic-gatedogfood PACKAGE, SUBNAME, DEFAULT_TYPE, TYPES, INDENT, BREAKOUT, ITEM... 746*0Sstevel@tonic-gate 747*0Sstevel@tonic-gateAn internal function to generate the embedded perl code that will regenerate 748*0Sstevel@tonic-gatethe constant subroutines. Parameters are the same as for C_constant. 749*0Sstevel@tonic-gate 750*0Sstevel@tonic-gate=cut 751*0Sstevel@tonic-gate 752*0Sstevel@tonic-gatesub dogfood { 753*0Sstevel@tonic-gate my ($package, $subname, $default_type, $what, $indent, $breakout, @items) 754*0Sstevel@tonic-gate = @_; 755*0Sstevel@tonic-gate my $result = <<"EOT"; 756*0Sstevel@tonic-gate /* When generated this function returned values for the list of names given 757*0Sstevel@tonic-gate in this section of perl code. Rather than manually editing these functions 758*0Sstevel@tonic-gate to add or remove constants, which would result in this comment and section 759*0Sstevel@tonic-gate of code becoming inaccurate, we recommend that you edit this section of 760*0Sstevel@tonic-gate code, and use it to regenerate a new set of constant functions which you 761*0Sstevel@tonic-gate then use to replace the originals. 762*0Sstevel@tonic-gate 763*0Sstevel@tonic-gate Regenerate these constant functions by feeding this entire source file to 764*0Sstevel@tonic-gate perl -x 765*0Sstevel@tonic-gate 766*0Sstevel@tonic-gate#!$^X -w 767*0Sstevel@tonic-gateuse ExtUtils::Constant qw (constant_types C_constant XS_constant); 768*0Sstevel@tonic-gate 769*0Sstevel@tonic-gateEOT 770*0Sstevel@tonic-gate $result .= dump_names ($default_type, $what, 0, {declare_types=>1}, @items); 771*0Sstevel@tonic-gate $result .= <<'EOT'; 772*0Sstevel@tonic-gate 773*0Sstevel@tonic-gateprint constant_types(); # macro defs 774*0Sstevel@tonic-gateEOT 775*0Sstevel@tonic-gate $package = perl_stringify($package); 776*0Sstevel@tonic-gate $result .= 777*0Sstevel@tonic-gate "foreach (C_constant (\"$package\", '$subname', '$default_type', \$types, "; 778*0Sstevel@tonic-gate # The form of the indent parameter isn't defined. (Yet) 779*0Sstevel@tonic-gate if (defined $indent) { 780*0Sstevel@tonic-gate require Data::Dumper; 781*0Sstevel@tonic-gate $Data::Dumper::Terse=1; 782*0Sstevel@tonic-gate $Data::Dumper::Terse=1; # Not used once. :-) 783*0Sstevel@tonic-gate chomp ($indent = Data::Dumper::Dumper ($indent)); 784*0Sstevel@tonic-gate $result .= $indent; 785*0Sstevel@tonic-gate } else { 786*0Sstevel@tonic-gate $result .= 'undef'; 787*0Sstevel@tonic-gate } 788*0Sstevel@tonic-gate $result .= ", $breakout" . ', @names) ) { 789*0Sstevel@tonic-gate print $_, "\n"; # C constant subs 790*0Sstevel@tonic-gate} 791*0Sstevel@tonic-gateprint "#### XS Section:\n"; 792*0Sstevel@tonic-gateprint XS_constant ("' . $package . '", $types); 793*0Sstevel@tonic-gate__END__ 794*0Sstevel@tonic-gate */ 795*0Sstevel@tonic-gate 796*0Sstevel@tonic-gate'; 797*0Sstevel@tonic-gate 798*0Sstevel@tonic-gate $result; 799*0Sstevel@tonic-gate} 800*0Sstevel@tonic-gate 801*0Sstevel@tonic-gate=item C_constant 802*0Sstevel@tonic-gate 803*0Sstevel@tonic-gateC_constant PACKAGE, SUBNAME, DEFAULT_TYPE, TYPES, INDENT, BREAKOUT, ITEM... 804*0Sstevel@tonic-gate 805*0Sstevel@tonic-gateA function that returns a B<list> of C subroutine definitions that return 806*0Sstevel@tonic-gatethe value and type of constants when passed the name by the XS wrapper. 807*0Sstevel@tonic-gateI<ITEM...> gives a list of constant names. Each can either be a string, 808*0Sstevel@tonic-gatewhich is taken as a C macro name, or a reference to a hash with the following 809*0Sstevel@tonic-gatekeys 810*0Sstevel@tonic-gate 811*0Sstevel@tonic-gate=over 8 812*0Sstevel@tonic-gate 813*0Sstevel@tonic-gate=item name 814*0Sstevel@tonic-gate 815*0Sstevel@tonic-gateThe name of the constant, as seen by the perl code. 816*0Sstevel@tonic-gate 817*0Sstevel@tonic-gate=item type 818*0Sstevel@tonic-gate 819*0Sstevel@tonic-gateThe type of the constant (I<IV>, I<NV> etc) 820*0Sstevel@tonic-gate 821*0Sstevel@tonic-gate=item value 822*0Sstevel@tonic-gate 823*0Sstevel@tonic-gateA C expression for the value of the constant, or a list of C expressions if 824*0Sstevel@tonic-gatethe type is aggregate. This defaults to the I<name> if not given. 825*0Sstevel@tonic-gate 826*0Sstevel@tonic-gate=item macro 827*0Sstevel@tonic-gate 828*0Sstevel@tonic-gateThe C pre-processor macro to use in the C<#ifdef>. This defaults to the 829*0Sstevel@tonic-gateI<name>, and is mainly used if I<value> is an C<enum>. If a reference an 830*0Sstevel@tonic-gatearray is passed then the first element is used in place of the C<#ifdef> 831*0Sstevel@tonic-gateline, and the second element in place of the C<#endif>. This allows 832*0Sstevel@tonic-gatepre-processor constructions such as 833*0Sstevel@tonic-gate 834*0Sstevel@tonic-gate #if defined (foo) 835*0Sstevel@tonic-gate #if !defined (bar) 836*0Sstevel@tonic-gate ... 837*0Sstevel@tonic-gate #endif 838*0Sstevel@tonic-gate #endif 839*0Sstevel@tonic-gate 840*0Sstevel@tonic-gateto be used to determine if a constant is to be defined. 841*0Sstevel@tonic-gate 842*0Sstevel@tonic-gateA "macro" 1 signals that the constant is always defined, so the C<#if>/C<#endif> 843*0Sstevel@tonic-gatetest is omitted. 844*0Sstevel@tonic-gate 845*0Sstevel@tonic-gate=item default 846*0Sstevel@tonic-gate 847*0Sstevel@tonic-gateDefault value to use (instead of C<croak>ing with "your vendor has not 848*0Sstevel@tonic-gatedefined...") to return if the macro isn't defined. Specify a reference to 849*0Sstevel@tonic-gatean array with type followed by value(s). 850*0Sstevel@tonic-gate 851*0Sstevel@tonic-gate=item pre 852*0Sstevel@tonic-gate 853*0Sstevel@tonic-gateC code to use before the assignment of the value of the constant. This allows 854*0Sstevel@tonic-gateyou to use temporary variables to extract a value from part of a C<struct> 855*0Sstevel@tonic-gateand return this as I<value>. This C code is places at the start of a block, 856*0Sstevel@tonic-gateso you can declare variables in it. 857*0Sstevel@tonic-gate 858*0Sstevel@tonic-gate=item post 859*0Sstevel@tonic-gate 860*0Sstevel@tonic-gateC code to place between the assignment of value (to a temporary) and the 861*0Sstevel@tonic-gatereturn from the function. This allows you to clear up anything in I<pre>. 862*0Sstevel@tonic-gateRarely needed. 863*0Sstevel@tonic-gate 864*0Sstevel@tonic-gate=item def_pre 865*0Sstevel@tonic-gate=item def_post 866*0Sstevel@tonic-gate 867*0Sstevel@tonic-gateEquivalents of I<pre> and I<post> for the default value. 868*0Sstevel@tonic-gate 869*0Sstevel@tonic-gate=item utf8 870*0Sstevel@tonic-gate 871*0Sstevel@tonic-gateGenerated internally. Is zero or undefined if name is 7 bit ASCII, 872*0Sstevel@tonic-gate"no" if the name is 8 bit (and so should only match if SvUTF8() is false), 873*0Sstevel@tonic-gate"yes" if the name is utf8 encoded. 874*0Sstevel@tonic-gate 875*0Sstevel@tonic-gateThe internals automatically clone any name with characters 128-255 but none 876*0Sstevel@tonic-gate256+ (ie one that could be either in bytes or utf8) into a second entry 877*0Sstevel@tonic-gatewhich is utf8 encoded. 878*0Sstevel@tonic-gate 879*0Sstevel@tonic-gate=back 880*0Sstevel@tonic-gate 881*0Sstevel@tonic-gateI<PACKAGE> is the name of the package, and is only used in comments inside the 882*0Sstevel@tonic-gategenerated C code. 883*0Sstevel@tonic-gate 884*0Sstevel@tonic-gateThe next 5 arguments can safely be given as C<undef>, and are mainly used 885*0Sstevel@tonic-gatefor recursion. I<SUBNAME> defaults to C<constant> if undefined. 886*0Sstevel@tonic-gate 887*0Sstevel@tonic-gateI<DEFAULT_TYPE> is the type returned by C<ITEM>s that don't specify their 888*0Sstevel@tonic-gatetype. In turn it defaults to I<IV>. I<TYPES> should be given either as a comma 889*0Sstevel@tonic-gateseparated list of types that the C subroutine C<constant> will generate or as 890*0Sstevel@tonic-gatea reference to a hash. I<DEFAULT_TYPE> will be added to the list if not 891*0Sstevel@tonic-gatepresent, as will any types given in the list of I<ITEM>s. The resultant list 892*0Sstevel@tonic-gateshould be the same list of types that C<XS_constant> is given. [Otherwise 893*0Sstevel@tonic-gateC<XS_constant> and C<C_constant> may differ in the number of parameters to the 894*0Sstevel@tonic-gateconstant function. I<INDENT> is currently unused and ignored. In future it may 895*0Sstevel@tonic-gatebe used to pass in information used to change the C indentation style used.] 896*0Sstevel@tonic-gateThe best way to maintain consistency is to pass in a hash reference and let 897*0Sstevel@tonic-gatethis function update it. 898*0Sstevel@tonic-gate 899*0Sstevel@tonic-gateI<BREAKOUT> governs when child functions of I<SUBNAME> are generated. If there 900*0Sstevel@tonic-gateare I<BREAKOUT> or more I<ITEM>s with the same length of name, then the code 901*0Sstevel@tonic-gateto switch between them is placed into a function named I<SUBNAME>_I<LEN>, for 902*0Sstevel@tonic-gateexample C<constant_5> for names 5 characters long. The default I<BREAKOUT> is 903*0Sstevel@tonic-gate3. A single C<ITEM> is always inlined. 904*0Sstevel@tonic-gate 905*0Sstevel@tonic-gate=cut 906*0Sstevel@tonic-gate 907*0Sstevel@tonic-gate# The parameter now BREAKOUT was previously documented as: 908*0Sstevel@tonic-gate# 909*0Sstevel@tonic-gate# I<NAMELEN> if defined signals that all the I<name>s of the I<ITEM>s are of 910*0Sstevel@tonic-gate# this length, and that the constant name passed in by perl is checked and 911*0Sstevel@tonic-gate# also of this length. It is used during recursion, and should be C<undef> 912*0Sstevel@tonic-gate# unless the caller has checked all the lengths during code generation, and 913*0Sstevel@tonic-gate# the generated subroutine is only to be called with a name of this length. 914*0Sstevel@tonic-gate# 915*0Sstevel@tonic-gate# As you can see it now performs this function during recursion by being a 916*0Sstevel@tonic-gate# scalar reference. 917*0Sstevel@tonic-gate 918*0Sstevel@tonic-gatesub C_constant { 919*0Sstevel@tonic-gate my ($package, $subname, $default_type, $what, $indent, $breakout, @items) 920*0Sstevel@tonic-gate = @_; 921*0Sstevel@tonic-gate $package ||= 'Foo'; 922*0Sstevel@tonic-gate $subname ||= 'constant'; 923*0Sstevel@tonic-gate # I'm not using this. But a hashref could be used for full formatting without 924*0Sstevel@tonic-gate # breaking this API 925*0Sstevel@tonic-gate # $indent ||= 0; 926*0Sstevel@tonic-gate 927*0Sstevel@tonic-gate my ($namelen, $items); 928*0Sstevel@tonic-gate if (ref $breakout) { 929*0Sstevel@tonic-gate # We are called recursively. We trust @items to be normalised, $what to 930*0Sstevel@tonic-gate # be a hashref, and pinch %$items from our parent to save recalculation. 931*0Sstevel@tonic-gate ($namelen, $items) = @$breakout; 932*0Sstevel@tonic-gate } else { 933*0Sstevel@tonic-gate if ($is_perl56) { 934*0Sstevel@tonic-gate # Need proper Unicode preserving hash keys. 935*0Sstevel@tonic-gate $items = {}; 936*0Sstevel@tonic-gate tie %$items, 'ExtUtils::Constant::Aaargh56Hash'; 937*0Sstevel@tonic-gate } 938*0Sstevel@tonic-gate $breakout ||= 3; 939*0Sstevel@tonic-gate $default_type ||= 'IV'; 940*0Sstevel@tonic-gate if (!ref $what) { 941*0Sstevel@tonic-gate # Convert line of the form IV,UV,NV to hash 942*0Sstevel@tonic-gate $what = {map {$_ => 1} split /,\s*/, ($what || '')}; 943*0Sstevel@tonic-gate # Figure out what types we're dealing with, and assign all unknowns to the 944*0Sstevel@tonic-gate # default type 945*0Sstevel@tonic-gate } 946*0Sstevel@tonic-gate my @new_items; 947*0Sstevel@tonic-gate foreach my $orig (@items) { 948*0Sstevel@tonic-gate my ($name, $item); 949*0Sstevel@tonic-gate if (ref $orig) { 950*0Sstevel@tonic-gate # Make a copy which is a normalised version of the ref passed in. 951*0Sstevel@tonic-gate $name = $orig->{name}; 952*0Sstevel@tonic-gate my ($type, $macro, $value) = @$orig{qw (type macro value)}; 953*0Sstevel@tonic-gate $type ||= $default_type; 954*0Sstevel@tonic-gate $what->{$type} = 1; 955*0Sstevel@tonic-gate $item = {name=>$name, type=>$type}; 956*0Sstevel@tonic-gate 957*0Sstevel@tonic-gate undef $macro if defined $macro and $macro eq $name; 958*0Sstevel@tonic-gate $item->{macro} = $macro if defined $macro; 959*0Sstevel@tonic-gate undef $value if defined $value and $value eq $name; 960*0Sstevel@tonic-gate $item->{value} = $value if defined $value; 961*0Sstevel@tonic-gate foreach my $key (qw(default pre post def_pre def_post)) { 962*0Sstevel@tonic-gate my $value = $orig->{$key}; 963*0Sstevel@tonic-gate $item->{$key} = $value if defined $value; 964*0Sstevel@tonic-gate # warn "$key $value"; 965*0Sstevel@tonic-gate } 966*0Sstevel@tonic-gate } else { 967*0Sstevel@tonic-gate $name = $orig; 968*0Sstevel@tonic-gate $item = {name=>$name, type=>$default_type}; 969*0Sstevel@tonic-gate $what->{$default_type} = 1; 970*0Sstevel@tonic-gate } 971*0Sstevel@tonic-gate warn "ExtUtils::Constant doesn't know how to handle values of type $_ used in macro $name" unless defined $XS_Constant{$item->{type}}; 972*0Sstevel@tonic-gate # tr///c is broken on 5.6.1 for utf8, so my original tr/\0-\177//c 973*0Sstevel@tonic-gate # doesn't work. Upgrade to 5.8 974*0Sstevel@tonic-gate # if ($name !~ tr/\0-\177//c || $] < 5.005_50) { 975*0Sstevel@tonic-gate if ($name =~ tr/\0-\177// == length $name || $] < 5.005_50) { 976*0Sstevel@tonic-gate # No characters outside 7 bit ASCII. 977*0Sstevel@tonic-gate if (exists $items->{$name}) { 978*0Sstevel@tonic-gate die "Multiple definitions for macro $name"; 979*0Sstevel@tonic-gate } 980*0Sstevel@tonic-gate $items->{$name} = $item; 981*0Sstevel@tonic-gate } else { 982*0Sstevel@tonic-gate # No characters outside 8 bit. This is hardest. 983*0Sstevel@tonic-gate if (exists $items->{$name} and ref $items->{$name} ne 'ARRAY') { 984*0Sstevel@tonic-gate confess "Unexpected ASCII definition for macro $name"; 985*0Sstevel@tonic-gate } 986*0Sstevel@tonic-gate # Again, 5.6.1 tr broken, so s/5\.6.*/5\.8\.0/; 987*0Sstevel@tonic-gate # if ($name !~ tr/\0-\377//c) { 988*0Sstevel@tonic-gate if ($name =~ tr/\0-\377// == length $name) { 989*0Sstevel@tonic-gate# if ($] < 5.007) { 990*0Sstevel@tonic-gate# $name = pack "C*", unpack "U*", $name; 991*0Sstevel@tonic-gate# } 992*0Sstevel@tonic-gate $item->{utf8} = 'no'; 993*0Sstevel@tonic-gate $items->{$name}[1] = $item; 994*0Sstevel@tonic-gate push @new_items, $item; 995*0Sstevel@tonic-gate # Copy item, to create the utf8 variant. 996*0Sstevel@tonic-gate $item = {%$item}; 997*0Sstevel@tonic-gate } 998*0Sstevel@tonic-gate # Encode the name as utf8 bytes. 999*0Sstevel@tonic-gate unless ($is_perl56) { 1000*0Sstevel@tonic-gate utf8::encode($name); 1001*0Sstevel@tonic-gate } else { 1002*0Sstevel@tonic-gate# warn "Was >$name< " . length ${name}; 1003*0Sstevel@tonic-gate $name = pack 'C*', unpack 'C*', $name . pack 'U*'; 1004*0Sstevel@tonic-gate# warn "Now '${name}' " . length ${name}; 1005*0Sstevel@tonic-gate } 1006*0Sstevel@tonic-gate if ($items->{$name}[0]) { 1007*0Sstevel@tonic-gate die "Multiple definitions for macro $name"; 1008*0Sstevel@tonic-gate } 1009*0Sstevel@tonic-gate $item->{utf8} = 'yes'; 1010*0Sstevel@tonic-gate $item->{name} = $name; 1011*0Sstevel@tonic-gate $items->{$name}[0] = $item; 1012*0Sstevel@tonic-gate # We have need for the utf8 flag. 1013*0Sstevel@tonic-gate $what->{''} = 1; 1014*0Sstevel@tonic-gate } 1015*0Sstevel@tonic-gate push @new_items, $item; 1016*0Sstevel@tonic-gate } 1017*0Sstevel@tonic-gate @items = @new_items; 1018*0Sstevel@tonic-gate # use Data::Dumper; print Dumper @items; 1019*0Sstevel@tonic-gate } 1020*0Sstevel@tonic-gate my $params = params ($what); 1021*0Sstevel@tonic-gate 1022*0Sstevel@tonic-gate my ($body, @subs) = "static int\n$subname (pTHX_ const char *name"; 1023*0Sstevel@tonic-gate $body .= ", STRLEN len" unless defined $namelen; 1024*0Sstevel@tonic-gate $body .= ", int utf8" if $params->{''}; 1025*0Sstevel@tonic-gate $body .= ", IV *iv_return" if $params->{IV}; 1026*0Sstevel@tonic-gate $body .= ", NV *nv_return" if $params->{NV}; 1027*0Sstevel@tonic-gate $body .= ", const char **pv_return" if $params->{PV}; 1028*0Sstevel@tonic-gate $body .= ", SV **sv_return" if $params->{SV}; 1029*0Sstevel@tonic-gate $body .= ") {\n"; 1030*0Sstevel@tonic-gate 1031*0Sstevel@tonic-gate if (defined $namelen) { 1032*0Sstevel@tonic-gate # We are a child subroutine. Print the simple description 1033*0Sstevel@tonic-gate my $comment = 'When generated this function returned values for the list' 1034*0Sstevel@tonic-gate . ' of names given here. However, subsequent manual editing may have' 1035*0Sstevel@tonic-gate . ' added or removed some.'; 1036*0Sstevel@tonic-gate $body .= switch_clause (2, $comment, $namelen, $items, @items); 1037*0Sstevel@tonic-gate } else { 1038*0Sstevel@tonic-gate # We are the top level. 1039*0Sstevel@tonic-gate $body .= " /* Initially switch on the length of the name. */\n"; 1040*0Sstevel@tonic-gate $body .= dogfood ($package, $subname, $default_type, $what, $indent, 1041*0Sstevel@tonic-gate $breakout, @items); 1042*0Sstevel@tonic-gate $body .= " switch (len) {\n"; 1043*0Sstevel@tonic-gate # Need to group names of the same length 1044*0Sstevel@tonic-gate my @by_length; 1045*0Sstevel@tonic-gate foreach (@items) { 1046*0Sstevel@tonic-gate push @{$by_length[length $_->{name}]}, $_; 1047*0Sstevel@tonic-gate } 1048*0Sstevel@tonic-gate foreach my $i (0 .. $#by_length) { 1049*0Sstevel@tonic-gate next unless $by_length[$i]; # None of this length 1050*0Sstevel@tonic-gate $body .= " case $i:\n"; 1051*0Sstevel@tonic-gate if (@{$by_length[$i]} == 1) { 1052*0Sstevel@tonic-gate my $only_thing = $by_length[$i]->[0]; 1053*0Sstevel@tonic-gate if ($only_thing->{utf8}) { 1054*0Sstevel@tonic-gate if ($only_thing->{utf8} eq 'yes') { 1055*0Sstevel@tonic-gate # With utf8 on flag item is passed in element 0 1056*0Sstevel@tonic-gate $body .= match_clause ([$only_thing]); 1057*0Sstevel@tonic-gate } else { 1058*0Sstevel@tonic-gate # With utf8 off flag item is passed in element 1 1059*0Sstevel@tonic-gate $body .= match_clause ([undef, $only_thing]); 1060*0Sstevel@tonic-gate } 1061*0Sstevel@tonic-gate } else { 1062*0Sstevel@tonic-gate $body .= match_clause ($only_thing); 1063*0Sstevel@tonic-gate } 1064*0Sstevel@tonic-gate } elsif (@{$by_length[$i]} < $breakout) { 1065*0Sstevel@tonic-gate $body .= switch_clause (4, '', $i, $items, @{$by_length[$i]}); 1066*0Sstevel@tonic-gate } else { 1067*0Sstevel@tonic-gate # Only use the minimal set of parameters actually needed by the types 1068*0Sstevel@tonic-gate # of the names of this length. 1069*0Sstevel@tonic-gate my $what = {}; 1070*0Sstevel@tonic-gate foreach (@{$by_length[$i]}) { 1071*0Sstevel@tonic-gate $what->{$_->{type}} = 1; 1072*0Sstevel@tonic-gate $what->{''} = 1 if $_->{utf8}; 1073*0Sstevel@tonic-gate } 1074*0Sstevel@tonic-gate $params = params ($what); 1075*0Sstevel@tonic-gate push @subs, C_constant ($package, "${subname}_$i", $default_type, $what, 1076*0Sstevel@tonic-gate $indent, [$i, $items], @{$by_length[$i]}); 1077*0Sstevel@tonic-gate $body .= " return ${subname}_$i (aTHX_ name"; 1078*0Sstevel@tonic-gate $body .= ", utf8" if $params->{''}; 1079*0Sstevel@tonic-gate $body .= ", iv_return" if $params->{IV}; 1080*0Sstevel@tonic-gate $body .= ", nv_return" if $params->{NV}; 1081*0Sstevel@tonic-gate $body .= ", pv_return" if $params->{PV}; 1082*0Sstevel@tonic-gate $body .= ", sv_return" if $params->{SV}; 1083*0Sstevel@tonic-gate $body .= ");\n"; 1084*0Sstevel@tonic-gate } 1085*0Sstevel@tonic-gate $body .= " break;\n"; 1086*0Sstevel@tonic-gate } 1087*0Sstevel@tonic-gate $body .= " }\n"; 1088*0Sstevel@tonic-gate } 1089*0Sstevel@tonic-gate $body .= " return PERL_constant_NOTFOUND;\n}\n"; 1090*0Sstevel@tonic-gate return (@subs, $body); 1091*0Sstevel@tonic-gate} 1092*0Sstevel@tonic-gate 1093*0Sstevel@tonic-gate=item XS_constant PACKAGE, TYPES, SUBNAME, C_SUBNAME 1094*0Sstevel@tonic-gate 1095*0Sstevel@tonic-gateA function to generate the XS code to implement the perl subroutine 1096*0Sstevel@tonic-gateI<PACKAGE>::constant used by I<PACKAGE>::AUTOLOAD to load constants. 1097*0Sstevel@tonic-gateThis XS code is a wrapper around a C subroutine usually generated by 1098*0Sstevel@tonic-gateC<C_constant>, and usually named C<constant>. 1099*0Sstevel@tonic-gate 1100*0Sstevel@tonic-gateI<TYPES> should be given either as a comma separated list of types that the 1101*0Sstevel@tonic-gateC subroutine C<constant> will generate or as a reference to a hash. It should 1102*0Sstevel@tonic-gatebe the same list of types as C<C_constant> was given. 1103*0Sstevel@tonic-gate[Otherwise C<XS_constant> and C<C_constant> may have different ideas about 1104*0Sstevel@tonic-gatethe number of parameters passed to the C function C<constant>] 1105*0Sstevel@tonic-gate 1106*0Sstevel@tonic-gateYou can call the perl visible subroutine something other than C<constant> if 1107*0Sstevel@tonic-gateyou give the parameter I<SUBNAME>. The C subroutine it calls defaults to 1108*0Sstevel@tonic-gatethe name of the perl visible subroutine, unless you give the parameter 1109*0Sstevel@tonic-gateI<C_SUBNAME>. 1110*0Sstevel@tonic-gate 1111*0Sstevel@tonic-gate=cut 1112*0Sstevel@tonic-gate 1113*0Sstevel@tonic-gatesub XS_constant { 1114*0Sstevel@tonic-gate my $package = shift; 1115*0Sstevel@tonic-gate my $what = shift; 1116*0Sstevel@tonic-gate my $subname = shift; 1117*0Sstevel@tonic-gate my $C_subname = shift; 1118*0Sstevel@tonic-gate $subname ||= 'constant'; 1119*0Sstevel@tonic-gate $C_subname ||= $subname; 1120*0Sstevel@tonic-gate 1121*0Sstevel@tonic-gate if (!ref $what) { 1122*0Sstevel@tonic-gate # Convert line of the form IV,UV,NV to hash 1123*0Sstevel@tonic-gate $what = {map {$_ => 1} split /,\s*/, ($what)}; 1124*0Sstevel@tonic-gate } 1125*0Sstevel@tonic-gate my $params = params ($what); 1126*0Sstevel@tonic-gate my $type; 1127*0Sstevel@tonic-gate 1128*0Sstevel@tonic-gate my $xs = <<"EOT"; 1129*0Sstevel@tonic-gatevoid 1130*0Sstevel@tonic-gate$subname(sv) 1131*0Sstevel@tonic-gate PREINIT: 1132*0Sstevel@tonic-gate#ifdef dXSTARG 1133*0Sstevel@tonic-gate dXSTARG; /* Faster if we have it. */ 1134*0Sstevel@tonic-gate#else 1135*0Sstevel@tonic-gate dTARGET; 1136*0Sstevel@tonic-gate#endif 1137*0Sstevel@tonic-gate STRLEN len; 1138*0Sstevel@tonic-gate int type; 1139*0Sstevel@tonic-gateEOT 1140*0Sstevel@tonic-gate 1141*0Sstevel@tonic-gate if ($params->{IV}) { 1142*0Sstevel@tonic-gate $xs .= " IV iv;\n"; 1143*0Sstevel@tonic-gate } else { 1144*0Sstevel@tonic-gate $xs .= " /* IV\t\tiv;\tUncomment this if you need to return IVs */\n"; 1145*0Sstevel@tonic-gate } 1146*0Sstevel@tonic-gate if ($params->{NV}) { 1147*0Sstevel@tonic-gate $xs .= " NV nv;\n"; 1148*0Sstevel@tonic-gate } else { 1149*0Sstevel@tonic-gate $xs .= " /* NV\t\tnv;\tUncomment this if you need to return NVs */\n"; 1150*0Sstevel@tonic-gate } 1151*0Sstevel@tonic-gate if ($params->{PV}) { 1152*0Sstevel@tonic-gate $xs .= " const char *pv;\n"; 1153*0Sstevel@tonic-gate } else { 1154*0Sstevel@tonic-gate $xs .= 1155*0Sstevel@tonic-gate " /* const char\t*pv;\tUncomment this if you need to return PVs */\n"; 1156*0Sstevel@tonic-gate } 1157*0Sstevel@tonic-gate 1158*0Sstevel@tonic-gate $xs .= << 'EOT'; 1159*0Sstevel@tonic-gate INPUT: 1160*0Sstevel@tonic-gate SV * sv; 1161*0Sstevel@tonic-gate const char * s = SvPV(sv, len); 1162*0Sstevel@tonic-gateEOT 1163*0Sstevel@tonic-gate if ($params->{''}) { 1164*0Sstevel@tonic-gate $xs .= << 'EOT'; 1165*0Sstevel@tonic-gate INPUT: 1166*0Sstevel@tonic-gate int utf8 = SvUTF8(sv); 1167*0Sstevel@tonic-gateEOT 1168*0Sstevel@tonic-gate } 1169*0Sstevel@tonic-gate $xs .= << 'EOT'; 1170*0Sstevel@tonic-gate PPCODE: 1171*0Sstevel@tonic-gateEOT 1172*0Sstevel@tonic-gate 1173*0Sstevel@tonic-gate if ($params->{IV} xor $params->{NV}) { 1174*0Sstevel@tonic-gate $xs .= << "EOT"; 1175*0Sstevel@tonic-gate /* Change this to $C_subname(aTHX_ s, len, &iv, &nv); 1176*0Sstevel@tonic-gate if you need to return both NVs and IVs */ 1177*0Sstevel@tonic-gateEOT 1178*0Sstevel@tonic-gate } 1179*0Sstevel@tonic-gate $xs .= " type = $C_subname(aTHX_ s, len"; 1180*0Sstevel@tonic-gate $xs .= ', utf8' if $params->{''}; 1181*0Sstevel@tonic-gate $xs .= ', &iv' if $params->{IV}; 1182*0Sstevel@tonic-gate $xs .= ', &nv' if $params->{NV}; 1183*0Sstevel@tonic-gate $xs .= ', &pv' if $params->{PV}; 1184*0Sstevel@tonic-gate $xs .= ', &sv' if $params->{SV}; 1185*0Sstevel@tonic-gate $xs .= ");\n"; 1186*0Sstevel@tonic-gate 1187*0Sstevel@tonic-gate $xs .= << "EOT"; 1188*0Sstevel@tonic-gate /* Return 1 or 2 items. First is error message, or undef if no error. 1189*0Sstevel@tonic-gate Second, if present, is found value */ 1190*0Sstevel@tonic-gate switch (type) { 1191*0Sstevel@tonic-gate case PERL_constant_NOTFOUND: 1192*0Sstevel@tonic-gate sv = sv_2mortal(newSVpvf("%s is not a valid $package macro", s)); 1193*0Sstevel@tonic-gate PUSHs(sv); 1194*0Sstevel@tonic-gate break; 1195*0Sstevel@tonic-gate case PERL_constant_NOTDEF: 1196*0Sstevel@tonic-gate sv = sv_2mortal(newSVpvf( 1197*0Sstevel@tonic-gate "Your vendor has not defined $package macro %s, used", s)); 1198*0Sstevel@tonic-gate PUSHs(sv); 1199*0Sstevel@tonic-gate break; 1200*0Sstevel@tonic-gateEOT 1201*0Sstevel@tonic-gate 1202*0Sstevel@tonic-gate foreach $type (sort keys %XS_Constant) { 1203*0Sstevel@tonic-gate # '' marks utf8 flag needed. 1204*0Sstevel@tonic-gate next if $type eq ''; 1205*0Sstevel@tonic-gate $xs .= "\t/* Uncomment this if you need to return ${type}s\n" 1206*0Sstevel@tonic-gate unless $what->{$type}; 1207*0Sstevel@tonic-gate $xs .= " case PERL_constant_IS$type:\n"; 1208*0Sstevel@tonic-gate if (length $XS_Constant{$type}) { 1209*0Sstevel@tonic-gate $xs .= << "EOT"; 1210*0Sstevel@tonic-gate EXTEND(SP, 1); 1211*0Sstevel@tonic-gate PUSHs(&PL_sv_undef); 1212*0Sstevel@tonic-gate $XS_Constant{$type}; 1213*0Sstevel@tonic-gateEOT 1214*0Sstevel@tonic-gate } else { 1215*0Sstevel@tonic-gate # Do nothing. return (), which will be correctly interpreted as 1216*0Sstevel@tonic-gate # (undef, undef) 1217*0Sstevel@tonic-gate } 1218*0Sstevel@tonic-gate $xs .= " break;\n"; 1219*0Sstevel@tonic-gate unless ($what->{$type}) { 1220*0Sstevel@tonic-gate chop $xs; # Yes, another need for chop not chomp. 1221*0Sstevel@tonic-gate $xs .= " */\n"; 1222*0Sstevel@tonic-gate } 1223*0Sstevel@tonic-gate } 1224*0Sstevel@tonic-gate $xs .= << "EOT"; 1225*0Sstevel@tonic-gate default: 1226*0Sstevel@tonic-gate sv = sv_2mortal(newSVpvf( 1227*0Sstevel@tonic-gate "Unexpected return type %d while processing $package macro %s, used", 1228*0Sstevel@tonic-gate type, s)); 1229*0Sstevel@tonic-gate PUSHs(sv); 1230*0Sstevel@tonic-gate } 1231*0Sstevel@tonic-gateEOT 1232*0Sstevel@tonic-gate 1233*0Sstevel@tonic-gate return $xs; 1234*0Sstevel@tonic-gate} 1235*0Sstevel@tonic-gate 1236*0Sstevel@tonic-gate 1237*0Sstevel@tonic-gate=item autoload PACKAGE, VERSION, AUTOLOADER 1238*0Sstevel@tonic-gate 1239*0Sstevel@tonic-gateA function to generate the AUTOLOAD subroutine for the module I<PACKAGE> 1240*0Sstevel@tonic-gateI<VERSION> is the perl version the code should be backwards compatible with. 1241*0Sstevel@tonic-gateIt defaults to the version of perl running the subroutine. If I<AUTOLOADER> 1242*0Sstevel@tonic-gateis true, the AUTOLOAD subroutine falls back on AutoLoader::AUTOLOAD for all 1243*0Sstevel@tonic-gatenames that the constant() routine doesn't recognise. 1244*0Sstevel@tonic-gate 1245*0Sstevel@tonic-gate=cut 1246*0Sstevel@tonic-gate 1247*0Sstevel@tonic-gate# ' # Grr. syntax highlighters that don't grok pod. 1248*0Sstevel@tonic-gate 1249*0Sstevel@tonic-gatesub autoload { 1250*0Sstevel@tonic-gate my ($module, $compat_version, $autoloader) = @_; 1251*0Sstevel@tonic-gate $compat_version ||= $]; 1252*0Sstevel@tonic-gate croak "Can't maintain compatibility back as far as version $compat_version" 1253*0Sstevel@tonic-gate if $compat_version < 5; 1254*0Sstevel@tonic-gate my $func = "sub AUTOLOAD {\n" 1255*0Sstevel@tonic-gate . " # This AUTOLOAD is used to 'autoload' constants from the constant()\n" 1256*0Sstevel@tonic-gate . " # XS function."; 1257*0Sstevel@tonic-gate $func .= " If a constant is not found then control is passed\n" 1258*0Sstevel@tonic-gate . " # to the AUTOLOAD in AutoLoader." if $autoloader; 1259*0Sstevel@tonic-gate 1260*0Sstevel@tonic-gate 1261*0Sstevel@tonic-gate $func .= "\n\n" 1262*0Sstevel@tonic-gate . " my \$constname;\n"; 1263*0Sstevel@tonic-gate $func .= 1264*0Sstevel@tonic-gate " our \$AUTOLOAD;\n" if ($compat_version >= 5.006); 1265*0Sstevel@tonic-gate 1266*0Sstevel@tonic-gate $func .= <<"EOT"; 1267*0Sstevel@tonic-gate (\$constname = \$AUTOLOAD) =~ s/.*:://; 1268*0Sstevel@tonic-gate croak "&${module}::constant not defined" if \$constname eq 'constant'; 1269*0Sstevel@tonic-gate my (\$error, \$val) = constant(\$constname); 1270*0Sstevel@tonic-gateEOT 1271*0Sstevel@tonic-gate 1272*0Sstevel@tonic-gate if ($autoloader) { 1273*0Sstevel@tonic-gate $func .= <<'EOT'; 1274*0Sstevel@tonic-gate if ($error) { 1275*0Sstevel@tonic-gate if ($error =~ /is not a valid/) { 1276*0Sstevel@tonic-gate $AutoLoader::AUTOLOAD = $AUTOLOAD; 1277*0Sstevel@tonic-gate goto &AutoLoader::AUTOLOAD; 1278*0Sstevel@tonic-gate } else { 1279*0Sstevel@tonic-gate croak $error; 1280*0Sstevel@tonic-gate } 1281*0Sstevel@tonic-gate } 1282*0Sstevel@tonic-gateEOT 1283*0Sstevel@tonic-gate } else { 1284*0Sstevel@tonic-gate $func .= 1285*0Sstevel@tonic-gate " if (\$error) { croak \$error; }\n"; 1286*0Sstevel@tonic-gate } 1287*0Sstevel@tonic-gate 1288*0Sstevel@tonic-gate $func .= <<'END'; 1289*0Sstevel@tonic-gate { 1290*0Sstevel@tonic-gate no strict 'refs'; 1291*0Sstevel@tonic-gate # Fixed between 5.005_53 and 5.005_61 1292*0Sstevel@tonic-gate#XXX if ($] >= 5.00561) { 1293*0Sstevel@tonic-gate#XXX *$AUTOLOAD = sub () { $val }; 1294*0Sstevel@tonic-gate#XXX } 1295*0Sstevel@tonic-gate#XXX else { 1296*0Sstevel@tonic-gate *$AUTOLOAD = sub { $val }; 1297*0Sstevel@tonic-gate#XXX } 1298*0Sstevel@tonic-gate } 1299*0Sstevel@tonic-gate goto &$AUTOLOAD; 1300*0Sstevel@tonic-gate} 1301*0Sstevel@tonic-gate 1302*0Sstevel@tonic-gateEND 1303*0Sstevel@tonic-gate 1304*0Sstevel@tonic-gate return $func; 1305*0Sstevel@tonic-gate} 1306*0Sstevel@tonic-gate 1307*0Sstevel@tonic-gate 1308*0Sstevel@tonic-gate=item WriteMakefileSnippet 1309*0Sstevel@tonic-gate 1310*0Sstevel@tonic-gateWriteMakefileSnippet ATTRIBUTE =E<gt> VALUE [, ...] 1311*0Sstevel@tonic-gate 1312*0Sstevel@tonic-gateA function to generate perl code for Makefile.PL that will regenerate 1313*0Sstevel@tonic-gatethe constant subroutines. Parameters are named as passed to C<WriteConstants>, 1314*0Sstevel@tonic-gatewith the addition of C<INDENT> to specify the number of leading spaces 1315*0Sstevel@tonic-gate(default 2). 1316*0Sstevel@tonic-gate 1317*0Sstevel@tonic-gateCurrently only C<INDENT>, C<NAME>, C<DEFAULT_TYPE>, C<NAMES>, C<C_FILE> and 1318*0Sstevel@tonic-gateC<XS_FILE> are recognised. 1319*0Sstevel@tonic-gate 1320*0Sstevel@tonic-gate=cut 1321*0Sstevel@tonic-gate 1322*0Sstevel@tonic-gatesub WriteMakefileSnippet { 1323*0Sstevel@tonic-gate my %args = @_; 1324*0Sstevel@tonic-gate my $indent = $args{INDENT} || 2; 1325*0Sstevel@tonic-gate 1326*0Sstevel@tonic-gate my $result = <<"EOT"; 1327*0Sstevel@tonic-gateExtUtils::Constant::WriteConstants( 1328*0Sstevel@tonic-gate NAME => '$args{NAME}', 1329*0Sstevel@tonic-gate NAMES => \\\@names, 1330*0Sstevel@tonic-gate DEFAULT_TYPE => '$args{DEFAULT_TYPE}', 1331*0Sstevel@tonic-gateEOT 1332*0Sstevel@tonic-gate foreach (qw (C_FILE XS_FILE)) { 1333*0Sstevel@tonic-gate next unless exists $args{$_}; 1334*0Sstevel@tonic-gate $result .= sprintf " %-12s => '%s',\n", 1335*0Sstevel@tonic-gate $_, $args{$_}; 1336*0Sstevel@tonic-gate } 1337*0Sstevel@tonic-gate $result .= <<'EOT'; 1338*0Sstevel@tonic-gate ); 1339*0Sstevel@tonic-gateEOT 1340*0Sstevel@tonic-gate 1341*0Sstevel@tonic-gate $result =~ s/^/' 'x$indent/gem; 1342*0Sstevel@tonic-gate return dump_names ($args{DEFAULT_TYPE}, undef, $indent, undef, 1343*0Sstevel@tonic-gate @{$args{NAMES}}) 1344*0Sstevel@tonic-gate . $result; 1345*0Sstevel@tonic-gate} 1346*0Sstevel@tonic-gate 1347*0Sstevel@tonic-gate=item WriteConstants ATTRIBUTE =E<gt> VALUE [, ...] 1348*0Sstevel@tonic-gate 1349*0Sstevel@tonic-gateWrites a file of C code and a file of XS code which you should C<#include> 1350*0Sstevel@tonic-gateand C<INCLUDE> in the C and XS sections respectively of your module's XS 1351*0Sstevel@tonic-gatecode. You probably want to do this in your C<Makefile.PL>, so that you can 1352*0Sstevel@tonic-gateeasily edit the list of constants without touching the rest of your module. 1353*0Sstevel@tonic-gateThe attributes supported are 1354*0Sstevel@tonic-gate 1355*0Sstevel@tonic-gate=over 4 1356*0Sstevel@tonic-gate 1357*0Sstevel@tonic-gate=item NAME 1358*0Sstevel@tonic-gate 1359*0Sstevel@tonic-gateName of the module. This must be specified 1360*0Sstevel@tonic-gate 1361*0Sstevel@tonic-gate=item DEFAULT_TYPE 1362*0Sstevel@tonic-gate 1363*0Sstevel@tonic-gateThe default type for the constants. If not specified C<IV> is assumed. 1364*0Sstevel@tonic-gate 1365*0Sstevel@tonic-gate=item BREAKOUT_AT 1366*0Sstevel@tonic-gate 1367*0Sstevel@tonic-gateThe names of the constants are grouped by length. Generate child subroutines 1368*0Sstevel@tonic-gatefor each group with this number or more names in. 1369*0Sstevel@tonic-gate 1370*0Sstevel@tonic-gate=item NAMES 1371*0Sstevel@tonic-gate 1372*0Sstevel@tonic-gateAn array of constants' names, either scalars containing names, or hashrefs 1373*0Sstevel@tonic-gateas detailed in L<"C_constant">. 1374*0Sstevel@tonic-gate 1375*0Sstevel@tonic-gate=item C_FILE 1376*0Sstevel@tonic-gate 1377*0Sstevel@tonic-gateThe name of the file to write containing the C code. The default is 1378*0Sstevel@tonic-gateC<const-c.inc>. The C<-> in the name ensures that the file can't be 1379*0Sstevel@tonic-gatemistaken for anything related to a legitimate perl package name, and 1380*0Sstevel@tonic-gatenot naming the file C<.c> avoids having to override Makefile.PL's 1381*0Sstevel@tonic-gateC<.xs> to C<.c> rules. 1382*0Sstevel@tonic-gate 1383*0Sstevel@tonic-gate=item XS_FILE 1384*0Sstevel@tonic-gate 1385*0Sstevel@tonic-gateThe name of the file to write containing the XS code. The default is 1386*0Sstevel@tonic-gateC<const-xs.inc>. 1387*0Sstevel@tonic-gate 1388*0Sstevel@tonic-gate=item SUBNAME 1389*0Sstevel@tonic-gate 1390*0Sstevel@tonic-gateThe perl visible name of the XS subroutine generated which will return the 1391*0Sstevel@tonic-gateconstants. The default is C<constant>. 1392*0Sstevel@tonic-gate 1393*0Sstevel@tonic-gate=item C_SUBNAME 1394*0Sstevel@tonic-gate 1395*0Sstevel@tonic-gateThe name of the C subroutine generated which will return the constants. 1396*0Sstevel@tonic-gateThe default is I<SUBNAME>. Child subroutines have C<_> and the name 1397*0Sstevel@tonic-gatelength appended, so constants with 10 character names would be in 1398*0Sstevel@tonic-gateC<constant_10> with the default I<XS_SUBNAME>. 1399*0Sstevel@tonic-gate 1400*0Sstevel@tonic-gate=back 1401*0Sstevel@tonic-gate 1402*0Sstevel@tonic-gate=cut 1403*0Sstevel@tonic-gate 1404*0Sstevel@tonic-gatesub WriteConstants { 1405*0Sstevel@tonic-gate my %ARGS = 1406*0Sstevel@tonic-gate ( # defaults 1407*0Sstevel@tonic-gate C_FILE => 'const-c.inc', 1408*0Sstevel@tonic-gate XS_FILE => 'const-xs.inc', 1409*0Sstevel@tonic-gate SUBNAME => 'constant', 1410*0Sstevel@tonic-gate DEFAULT_TYPE => 'IV', 1411*0Sstevel@tonic-gate @_); 1412*0Sstevel@tonic-gate 1413*0Sstevel@tonic-gate $ARGS{C_SUBNAME} ||= $ARGS{SUBNAME}; # No-one sane will have C_SUBNAME eq '0' 1414*0Sstevel@tonic-gate 1415*0Sstevel@tonic-gate croak "Module name not specified" unless length $ARGS{NAME}; 1416*0Sstevel@tonic-gate 1417*0Sstevel@tonic-gate open my $c_fh, ">$ARGS{C_FILE}" or die "Can't open $ARGS{C_FILE}: $!"; 1418*0Sstevel@tonic-gate open my $xs_fh, ">$ARGS{XS_FILE}" or die "Can't open $ARGS{XS_FILE}: $!"; 1419*0Sstevel@tonic-gate 1420*0Sstevel@tonic-gate # As this subroutine is intended to make code that isn't edited, there's no 1421*0Sstevel@tonic-gate # need for the user to specify any types that aren't found in the list of 1422*0Sstevel@tonic-gate # names. 1423*0Sstevel@tonic-gate my $types = {}; 1424*0Sstevel@tonic-gate 1425*0Sstevel@tonic-gate print $c_fh constant_types(); # macro defs 1426*0Sstevel@tonic-gate print $c_fh "\n"; 1427*0Sstevel@tonic-gate 1428*0Sstevel@tonic-gate # indent is still undef. Until anyone implements indent style rules with it. 1429*0Sstevel@tonic-gate foreach (C_constant ($ARGS{NAME}, $ARGS{C_SUBNAME}, $ARGS{DEFAULT_TYPE}, 1430*0Sstevel@tonic-gate $types, undef, $ARGS{BREAKOUT_AT}, @{$ARGS{NAMES}})) { 1431*0Sstevel@tonic-gate print $c_fh $_, "\n"; # C constant subs 1432*0Sstevel@tonic-gate } 1433*0Sstevel@tonic-gate print $xs_fh XS_constant ($ARGS{NAME}, $types, $ARGS{XS_SUBNAME}, 1434*0Sstevel@tonic-gate $ARGS{C_SUBNAME}); 1435*0Sstevel@tonic-gate 1436*0Sstevel@tonic-gate close $c_fh or warn "Error closing $ARGS{C_FILE}: $!"; 1437*0Sstevel@tonic-gate close $xs_fh or warn "Error closing $ARGS{XS_FILE}: $!"; 1438*0Sstevel@tonic-gate} 1439*0Sstevel@tonic-gate 1440*0Sstevel@tonic-gatepackage ExtUtils::Constant::Aaargh56Hash; 1441*0Sstevel@tonic-gate# A support module (hack) to provide sane Unicode hash keys on 5.6.x perl 1442*0Sstevel@tonic-gateuse strict; 1443*0Sstevel@tonic-gaterequire Tie::Hash if $ExtUtils::Constant::is_perl56; 1444*0Sstevel@tonic-gateuse vars '@ISA'; 1445*0Sstevel@tonic-gate@ISA = 'Tie::StdHash'; 1446*0Sstevel@tonic-gate 1447*0Sstevel@tonic-gate#my $a; 1448*0Sstevel@tonic-gate# Storing the values as concatenated BER encoded numbers is actually going to 1449*0Sstevel@tonic-gate# be terser than using UTF8 :-) 1450*0Sstevel@tonic-gate# And the tests are slightly faster. Ops are bad, m'kay 1451*0Sstevel@tonic-gatesub to_key {pack "w*", unpack "U*", ($_[0] . pack "U*")}; 1452*0Sstevel@tonic-gatesub from_key {defined $_[0] ? pack "U*", unpack 'w*', $_[0] : undef}; 1453*0Sstevel@tonic-gate 1454*0Sstevel@tonic-gatesub STORE { $_[0]->{to_key($_[1])} = $_[2] } 1455*0Sstevel@tonic-gatesub FETCH { $_[0]->{to_key($_[1])} } 1456*0Sstevel@tonic-gatesub FIRSTKEY { my $a = scalar keys %{$_[0]}; from_key (each %{$_[0]}) } 1457*0Sstevel@tonic-gatesub NEXTKEY { from_key (each %{$_[0]}) } 1458*0Sstevel@tonic-gatesub EXISTS { exists $_[0]->{to_key($_[1])} } 1459*0Sstevel@tonic-gatesub DELETE { delete $_[0]->{to_key($_[1])} } 1460*0Sstevel@tonic-gate 1461*0Sstevel@tonic-gate#END {warn "$a accesses";} 1462*0Sstevel@tonic-gate1; 1463*0Sstevel@tonic-gate__END__ 1464*0Sstevel@tonic-gate 1465*0Sstevel@tonic-gate=back 1466*0Sstevel@tonic-gate 1467*0Sstevel@tonic-gate=head1 AUTHOR 1468*0Sstevel@tonic-gate 1469*0Sstevel@tonic-gateNicholas Clark <nick@ccl4.org> based on the code in C<h2xs> by Larry Wall and 1470*0Sstevel@tonic-gateothers 1471*0Sstevel@tonic-gate 1472*0Sstevel@tonic-gate=cut 1473