and I for the default value.
=item utf8
Generated internally. Is zero or undefined if name is 7 bit ASCII,
"no" if the name is 8 bit (and so should only match if SvUTF8() is false),
"yes" if the name is utf8 encoded.
The internals automatically clone any name with characters 128-255 but none
256+ (ie one that could be either in bytes or utf8) into a second entry
which is utf8 encoded.
=item weight
Optional sorting weight for names, to determine the order of
linear testing when multiple names fall in the same case of a switch clause.
Higher comes earlier, undefined defaults to zero.
=back
In the argument hashref, I is the name of the package, and is only
used in comments inside the generated C code. I defaults to
C if undefined.
I is the type returned by Cs that don't specify their
type. It defaults to the value of C. I should be given
either as a comma separated list of types that the C subroutine I
will generate or as a reference to a hash. I will be added to
the list if not present, as will any types given in the list of Is. The
resultant list should be the same list of types that C is
given. [Otherwise C and C may differ in the number of
parameters to the constant function. I is currently unused and
ignored. In future it may be used to pass in information used to change the C
indentation style used.] The best way to maintain consistency is to pass in a
hash reference and let this function update it.
I governs when child functions of I are generated. If there
are I or more Is with the same length of name, then the code
to switch between them is placed into a function named I_I, for
example C for names 5 characters long. The default I is
3. A single C is always inlined.
=cut
# The parameter now BREAKOUT was previously documented as:
#
# I if defined signals that all the Is of the Is are of
# this length, and that the constant name passed in by perl is checked and
# also of this length. It is used during recursion, and should be C
# unless the caller has checked all the lengths during code generation, and
# the generated subroutine is only to be called with a name of this length.
#
# As you can see it now performs this function during recursion by being a
# scalar reference.
sub C_constant {
my ($self, $args, @items) = @_;
my ($package, $subname, $default_type, $what, $indent, $breakout) =
@{$args}{qw(package subname default_type types indent breakout)};
$package ||= 'Foo';
$subname ||= 'constant';
# I'm not using this. But a hashref could be used for full formatting without
# breaking this API
# $indent ||= 0;
my ($namelen, $items);
if (ref $breakout) {
# We are called recursively. We trust @items to be normalised, $what to
# be a hashref, and pinch %$items from our parent to save recalculation.
($namelen, $items) = @$breakout;
} else {
$items = {};
if ($is_perl56) {
# Need proper Unicode preserving hash keys.
require ExtUtils::Constant::Aaargh56Hash;
tie %$items, 'ExtUtils::Constant::Aaargh56Hash';
}
$breakout ||= 3;
$default_type ||= $self->default_type();
if (!ref $what) {
# Convert line of the form IV,UV,NV to hash
$what = {map {$_ => 1} split /,\s*/, ($what || '')};
# Figure out what types we're dealing with, and assign all unknowns to the
# default type
}
@items = $self->normalise_items ({}, $default_type, $what, $items, @items);
# use Data::Dumper; print Dumper @items;
}
my $params = $self->params ($what);
# Probably "static int"
my ($body, @subs);
$body = $self->C_constant_return_type($params) . "\n$subname ("
# Eg "pTHX_ "
. $self->C_constant_prefix_param_defintion($params)
# Probably "const char *name"
. $self->name_param_definition($params);
# Something like ", STRLEN len"
$body .= ", " . $self->namelen_param_definition($params)
unless defined $namelen;
$body .= $self->C_constant_other_params_defintion($params);
$body .= ") {\n";
if (defined $namelen) {
# We are a child subroutine. Print the simple description
my $comment = 'When generated this function returned values for the list'
. ' of names given here. However, subsequent manual editing may have'
. ' added or removed some.';
$body .= $self->switch_clause ({indent=>2, comment=>$comment},
$namelen, $items, @items);
} else {
# We are the top level.
$body .= " /* Initially switch on the length of the name. */\n";
$body .= $self->dogfood ({package => $package, subname => $subname,
default_type => $default_type, what => $what,
indent => $indent, breakout => $breakout},
@items);
$body .= ' switch ('.$self->namelen_param().") {\n";
# Need to group names of the same length
my @by_length;
foreach (@items) {
push @{$by_length[length $_->{name}]}, $_;
}
foreach my $i (0 .. $#by_length) {
next unless $by_length[$i]; # None of this length
$body .= " case $i:\n";
if (@{$by_length[$i]} == 1) {
my $only_thing = $by_length[$i]->[0];
if ($only_thing->{utf8}) {
if ($only_thing->{utf8} eq 'yes') {
# With utf8 on flag item is passed in element 0
$body .= $self->match_clause (undef, [$only_thing]);
} else {
# With utf8 off flag item is passed in element 1
$body .= $self->match_clause (undef, [undef, $only_thing]);
}
} else {
$body .= $self->match_clause (undef, $only_thing);
}
} elsif (@{$by_length[$i]} < $breakout) {
$body .= $self->switch_clause ({indent=>4},
$i, $items, @{$by_length[$i]});
} else {
# Only use the minimal set of parameters actually needed by the types
# of the names of this length.
my $what = {};
foreach (@{$by_length[$i]}) {
$what->{$_->{type}} = 1;
$what->{''} = 1 if $_->{utf8};
}
$params = $self->params ($what);
push @subs, $self->C_constant ({package=>$package,
subname=>"${subname}_$i",
default_type => $default_type,
types => $what, indent => $indent,
breakout => [$i, $items]},
@{$by_length[$i]});
$body .= " return ${subname}_$i ("
# Eg "aTHX_ "
. $self->C_constant_prefix_param($params)
# Probably "name"
. $self->name_param($params);
$body .= $self->C_constant_other_params($params);
$body .= ");\n";
}
$body .= " break;\n";
}
$body .= " }\n";
}
my $notfound = $self->return_statement_for_notfound();
$body .= " $notfound\n" if $notfound;
$body .= "}\n";
return (@subs, $body);
}
1;
__END__
=back
=head1 BUGS
Not everything is documented yet.
Probably others.
=head1 AUTHOR
Nicholas Clark based on the code in C by Larry Wall and
others