xref: /onnv-gate/usr/src/cmd/perl/5.8.4/distrib/lib/ExtUtils/Constant.pm (revision 0:68f95e015346)
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