summaryrefslogtreecommitdiffstats
path: root/gnu/usr.bin/perl/dist/ExtUtils-ParseXS/lib/ExtUtils
diff options
context:
space:
mode:
authorsthen <sthen@openbsd.org>2013-03-25 20:06:16 +0000
committersthen <sthen@openbsd.org>2013-03-25 20:06:16 +0000
commit898184e3e61f9129feb5978fad5a8c6865f00b92 (patch)
tree56f32aefc1eed60b534611007c7856f82697a205 /gnu/usr.bin/perl/dist/ExtUtils-ParseXS/lib/ExtUtils
parentPGSHIFT -> PAGE_SHIFT (diff)
downloadwireguard-openbsd-898184e3e61f9129feb5978fad5a8c6865f00b92.tar.xz
wireguard-openbsd-898184e3e61f9129feb5978fad5a8c6865f00b92.zip
import perl 5.16.3 from CPAN - worked on by Andrew Fresh and myself
Diffstat (limited to 'gnu/usr.bin/perl/dist/ExtUtils-ParseXS/lib/ExtUtils')
-rw-r--r--gnu/usr.bin/perl/dist/ExtUtils-ParseXS/lib/ExtUtils/ParseXS.pm1993
-rw-r--r--gnu/usr.bin/perl/dist/ExtUtils-ParseXS/lib/ExtUtils/ParseXS.pod161
-rw-r--r--gnu/usr.bin/perl/dist/ExtUtils-ParseXS/lib/ExtUtils/ParseXS/Constants.pm42
-rw-r--r--gnu/usr.bin/perl/dist/ExtUtils-ParseXS/lib/ExtUtils/ParseXS/CountLines.pm54
-rw-r--r--gnu/usr.bin/perl/dist/ExtUtils-ParseXS/lib/ExtUtils/ParseXS/Utilities.pm924
-rw-r--r--gnu/usr.bin/perl/dist/ExtUtils-ParseXS/lib/ExtUtils/Typemaps.pm1031
-rw-r--r--gnu/usr.bin/perl/dist/ExtUtils-ParseXS/lib/ExtUtils/Typemaps/Cmd.pm168
-rw-r--r--gnu/usr.bin/perl/dist/ExtUtils-ParseXS/lib/ExtUtils/Typemaps/InputMap.pm116
-rw-r--r--gnu/usr.bin/perl/dist/ExtUtils-ParseXS/lib/ExtUtils/Typemaps/OutputMap.pm195
-rw-r--r--gnu/usr.bin/perl/dist/ExtUtils-ParseXS/lib/ExtUtils/Typemaps/Type.pm121
-rw-r--r--gnu/usr.bin/perl/dist/ExtUtils-ParseXS/lib/ExtUtils/xsubpp173
11 files changed, 4978 insertions, 0 deletions
diff --git a/gnu/usr.bin/perl/dist/ExtUtils-ParseXS/lib/ExtUtils/ParseXS.pm b/gnu/usr.bin/perl/dist/ExtUtils-ParseXS/lib/ExtUtils/ParseXS.pm
new file mode 100644
index 00000000000..883d9059311
--- /dev/null
+++ b/gnu/usr.bin/perl/dist/ExtUtils-ParseXS/lib/ExtUtils/ParseXS.pm
@@ -0,0 +1,1993 @@
+package ExtUtils::ParseXS;
+use strict;
+
+use 5.006001;
+use Cwd;
+use Config;
+use Exporter;
+use File::Basename;
+use File::Spec;
+use Symbol;
+
+our $VERSION;
+BEGIN {
+ $VERSION = '3.16';
+}
+use ExtUtils::ParseXS::Constants $VERSION;
+use ExtUtils::ParseXS::CountLines $VERSION;
+use ExtUtils::ParseXS::Utilities $VERSION;
+$VERSION = eval $VERSION if $VERSION =~ /_/;
+
+use ExtUtils::ParseXS::Utilities qw(
+ standard_typemap_locations
+ trim_whitespace
+ tidy_type
+ C_string
+ valid_proto_string
+ process_typemaps
+ make_targetable
+ map_type
+ standard_XS_defs
+ assign_func_args
+ analyze_preprocessor_statements
+ set_cond
+ Warn
+ current_line_number
+ blurt
+ death
+ check_conditional_preprocessor_statements
+ escape_file_for_line_directive
+ report_typemap_failure
+);
+
+our @ISA = qw(Exporter);
+our @EXPORT_OK = qw(
+ process_file
+ report_error_count
+);
+
+# The scalars in the line below remain as 'our' variables because pulling
+# them into $self led to build problems. In most cases, strings being
+# 'eval'-ed contain the variables' names hard-coded.
+our (
+ $Package, $func_name, $Full_func_name, $pname, $ALIAS,
+);
+
+our $self = bless {} => __PACKAGE__;
+
+sub process_file {
+
+ # Allow for $package->process_file(%hash) in the future
+ my ($pkg, %options) = @_ % 2 ? @_ : (__PACKAGE__, @_);
+
+ $self->{ProtoUsed} = exists $options{prototypes};
+
+ # Set defaults.
+ my %args = (
+ argtypes => 1,
+ csuffix => '.c',
+ except => 0,
+ hiertype => 0,
+ inout => 1,
+ linenumbers => 1,
+ optimize => 1,
+ output => \*STDOUT,
+ prototypes => 0,
+ typemap => [],
+ versioncheck => 1,
+ FH => Symbol::gensym(),
+ %options,
+ );
+ $args{except} = $args{except} ? ' TRY' : '';
+
+ # Global Constants
+
+ my ($Is_VMS, $SymSet);
+ if ($^O eq 'VMS') {
+ $Is_VMS = 1;
+ # Establish set of global symbols with max length 28, since xsubpp
+ # will later add the 'XS_' prefix.
+ require ExtUtils::XSSymSet;
+ $SymSet = ExtUtils::XSSymSet->new(28);
+ }
+ @{ $self->{XSStack} } = ({type => 'none'});
+ $self->{InitFileCode} = [ @ExtUtils::ParseXS::Constants::InitFileCode ];
+ $self->{Overload} = 0;
+ $self->{errors} = 0;
+ $self->{Fallback} = '&PL_sv_undef';
+
+ # Most of the 1500 lines below uses these globals. We'll have to
+ # clean this up sometime, probably. For now, we just pull them out
+ # of %args. -Ken
+
+ $self->{hiertype} = $args{hiertype};
+ $self->{WantPrototypes} = $args{prototypes};
+ $self->{WantVersionChk} = $args{versioncheck};
+ $self->{WantLineNumbers} = $args{linenumbers};
+ $self->{IncludedFiles} = {};
+
+ die "Missing required parameter 'filename'" unless $args{filename};
+ $self->{filepathname} = $args{filename};
+ ($self->{dir}, $self->{filename}) =
+ (dirname($args{filename}), basename($args{filename}));
+ $self->{filepathname} =~ s/\\/\\\\/g;
+ $self->{IncludedFiles}->{$args{filename}}++;
+
+ # Open the output file if given as a string. If they provide some
+ # other kind of reference, trust them that we can print to it.
+ if (not ref $args{output}) {
+ open my($fh), "> $args{output}" or die "Can't create $args{output}: $!";
+ $args{outfile} = $args{output};
+ $args{output} = $fh;
+ }
+
+ # Really, we shouldn't have to chdir() or select() in the first
+ # place. For now, just save and restore.
+ my $orig_cwd = cwd();
+ my $orig_fh = select();
+
+ chdir($self->{dir});
+ my $pwd = cwd();
+ my $csuffix = $args{csuffix};
+
+ if ($self->{WantLineNumbers}) {
+ my $cfile;
+ if ( $args{outfile} ) {
+ $cfile = $args{outfile};
+ }
+ else {
+ $cfile = $args{filename};
+ $cfile =~ s/\.xs$/$csuffix/i or $cfile .= $csuffix;
+ }
+ tie(*PSEUDO_STDOUT, 'ExtUtils::ParseXS::CountLines', $cfile, $args{output});
+ select PSEUDO_STDOUT;
+ }
+ else {
+ select $args{output};
+ }
+
+ $self->{typemap} = process_typemaps( $args{typemap}, $pwd );
+
+ my $END = "!End!\n\n"; # "impossible" keyword (multiple newline)
+
+ # Match an XS keyword
+ $self->{BLOCK_re} = '\s*(' .
+ join('|' => @ExtUtils::ParseXS::Constants::XSKeywords) .
+ "|$END)\\s*:";
+
+ our ($C_group_rex, $C_arg);
+ # Group in C (no support for comments or literals)
+ $C_group_rex = qr/ [({\[]
+ (?: (?> [^()\[\]{}]+ ) | (??{ $C_group_rex }) )*
+ [)}\]] /x;
+ # Chunk in C without comma at toplevel (no comments):
+ $C_arg = qr/ (?: (?> [^()\[\]{},"']+ )
+ | (??{ $C_group_rex })
+ | " (?: (?> [^\\"]+ )
+ | \\.
+ )* " # String literal
+ | ' (?: (?> [^\\']+ ) | \\. )* ' # Char literal
+ )* /xs;
+
+ # Since at this point we're ready to begin printing to the output file and
+ # reading from the input file, I want to get as much data as possible into
+ # the proto-object $self. That means assigning to $self and elements of
+ # %args referenced below this point.
+ # HOWEVER: This resulted in an error when I tried:
+ # $args{'s'} ---> $self->{s}.
+ # Use of uninitialized value in quotemeta at
+ # .../blib/lib/ExtUtils/ParseXS.pm line 733
+
+ foreach my $datum ( qw| argtypes except inout optimize | ) {
+ $self->{$datum} = $args{$datum};
+ }
+
+ # Identify the version of xsubpp used
+ print <<EOM;
+/*
+ * This file was generated automatically by ExtUtils::ParseXS version $VERSION from the
+ * contents of $self->{filename}. Do not edit this file, edit $self->{filename} instead.
+ *
+ * ANY CHANGES MADE HERE WILL BE LOST!
+ *
+ */
+
+EOM
+
+
+ print("#line 1 \"" . escape_file_for_line_directive($self->{filepathname}) . "\"\n")
+ if $self->{WantLineNumbers};
+
+ # Open the input file (using $self->{filename} which
+ # is a basename'd $args{filename} due to chdir above)
+ open($self->{FH}, '<', $self->{filename}) or die "cannot open $self->{filename}: $!\n";
+
+ firstmodule:
+ while (readline($self->{FH})) {
+ if (/^=/) {
+ my $podstartline = $.;
+ do {
+ if (/^=cut\s*$/) {
+ # We can't just write out a /* */ comment, as our embedded
+ # POD might itself be in a comment. We can't put a /**/
+ # comment inside #if 0, as the C standard says that the source
+ # file is decomposed into preprocessing characters in the stage
+ # before preprocessing commands are executed.
+ # I don't want to leave the text as barewords, because the spec
+ # isn't clear whether macros are expanded before or after
+ # preprocessing commands are executed, and someone pathological
+ # may just have defined one of the 3 words as a macro that does
+ # something strange. Multiline strings are illegal in C, so
+ # the "" we write must be a string literal. And they aren't
+ # concatenated until 2 steps later, so we are safe.
+ # - Nicholas Clark
+ print("#if 0\n \"Skipped embedded POD.\"\n#endif\n");
+ printf("#line %d \"%s\"\n", $. + 1, escape_file_for_line_directive($self->{filepathname}))
+ if $self->{WantLineNumbers};
+ next firstmodule
+ }
+
+ } while (readline($self->{FH}));
+ # At this point $. is at end of file so die won't state the start
+ # of the problem, and as we haven't yet read any lines &death won't
+ # show the correct line in the message either.
+ die ("Error: Unterminated pod in $self->{filename}, line $podstartline\n")
+ unless $self->{lastline};
+ }
+ last if ($Package, $self->{Prefix}) =
+ /^MODULE\s*=\s*[\w:]+(?:\s+PACKAGE\s*=\s*([\w:]+))?(?:\s+PREFIX\s*=\s*(\S+))?\s*$/;
+
+ print $_;
+ }
+ unless (defined $_) {
+ warn "Didn't find a 'MODULE ... PACKAGE ... PREFIX' line\n";
+ exit 0; # Not a fatal error for the caller process
+ }
+
+ print 'ExtUtils::ParseXS::CountLines'->end_marker, "\n" if $self->{WantLineNumbers};
+
+ standard_XS_defs();
+
+ print 'ExtUtils::ParseXS::CountLines'->end_marker, "\n" if $self->{WantLineNumbers};
+
+ $self->{lastline} = $_;
+ $self->{lastline_no} = $.;
+
+ my $BootCode_ref = [];
+ my $XSS_work_idx = 0;
+ my $cpp_next_tmp = 'XSubPPtmpAAAA';
+ PARAGRAPH:
+ while ($self->fetch_para()) {
+ my $outlist_ref = [];
+ # Print initial preprocessor statements and blank lines
+ while (@{ $self->{line} } && $self->{line}->[0] !~ /^[^\#]/) {
+ my $ln = shift(@{ $self->{line} });
+ print $ln, "\n";
+ next unless $ln =~ /^\#\s*((if)(?:n?def)?|elsif|else|endif)\b/;
+ my $statement = $+;
+ ( $self, $XSS_work_idx, $BootCode_ref ) =
+ analyze_preprocessor_statements(
+ $self, $statement, $XSS_work_idx, $BootCode_ref
+ );
+ }
+
+ next PARAGRAPH unless @{ $self->{line} };
+
+ if ($XSS_work_idx && !$self->{XSStack}->[$XSS_work_idx]{varname}) {
+ # We are inside an #if, but have not yet #defined its xsubpp variable.
+ print "#define $cpp_next_tmp 1\n\n";
+ push(@{ $self->{InitFileCode} }, "#if $cpp_next_tmp\n");
+ push(@{ $BootCode_ref }, "#if $cpp_next_tmp");
+ $self->{XSStack}->[$XSS_work_idx]{varname} = $cpp_next_tmp++;
+ }
+
+ $self->death(
+ "Code is not inside a function"
+ ." (maybe last function was ended by a blank line "
+ ." followed by a statement on column one?)")
+ if $self->{line}->[0] =~ /^\s/;
+
+ # initialize info arrays
+ foreach my $member (qw(args_match var_types defaults arg_list
+ argtype_seen in_out lengthof))
+ {
+ $self->{$member} = {};
+ }
+ $self->{proto_arg} = [];
+ $self->{processing_arg_with_types} = undef;
+ $self->{proto_in_this_xsub} = undef;
+ $self->{scope_in_this_xsub} = undef;
+ $self->{interface} = undef;
+ $self->{interface_macro} = 'XSINTERFACE_FUNC';
+ $self->{interface_macro_set} = 'XSINTERFACE_FUNC_SET';
+ $self->{ProtoThisXSUB} = $self->{WantPrototypes};
+ $self->{ScopeThisXSUB} = 0;
+
+ my $xsreturn = 0;
+
+ $_ = shift(@{ $self->{line} });
+ while (my $kwd = $self->check_keyword("REQUIRE|PROTOTYPES|EXPORT_XSUB_SYMBOLS|FALLBACK|VERSIONCHECK|INCLUDE(?:_COMMAND)?|SCOPE")) {
+ my $method = $kwd . "_handler";
+ $self->$method($_);
+ next PARAGRAPH unless @{ $self->{line} };
+ $_ = shift(@{ $self->{line} });
+ }
+
+ if ($self->check_keyword("BOOT")) {
+ check_conditional_preprocessor_statements($self);
+ push (@{ $BootCode_ref }, "#line $self->{line_no}->[@{ $self->{line_no} } - @{ $self->{line} }] \""
+ . escape_file_for_line_directive($self->{filepathname}) . "\"")
+ if $self->{WantLineNumbers} && $self->{line}->[0] !~ /^\s*#\s*line\b/;
+ push (@{ $BootCode_ref }, @{ $self->{line} }, "");
+ next PARAGRAPH;
+ }
+
+ # extract return type, function name and arguments
+ ($self->{ret_type}) = tidy_type($_);
+ my $RETVAL_no_return = 1 if $self->{ret_type} =~ s/^NO_OUTPUT\s+//;
+
+ # Allow one-line ANSI-like declaration
+ unshift @{ $self->{line} }, $2
+ if $self->{argtypes}
+ and $self->{ret_type} =~ s/^(.*?\w.*?)\s*\b(\w+\s*\(.*)/$1/s;
+
+ # a function definition needs at least 2 lines
+ $self->blurt("Error: Function definition too short '$self->{ret_type}'"), next PARAGRAPH
+ unless @{ $self->{line} };
+
+ my $externC = 1 if $self->{ret_type} =~ s/^extern "C"\s+//;
+ my $static = 1 if $self->{ret_type} =~ s/^static\s+//;
+
+ my $func_header = shift(@{ $self->{line} });
+ $self->blurt("Error: Cannot parse function definition from '$func_header'"), next PARAGRAPH
+ unless $func_header =~ /^(?:([\w:]*)::)?(\w+)\s*\(\s*(.*?)\s*\)\s*(const)?\s*(;\s*)?$/s;
+
+ my ($class, $orig_args);
+ ($class, $func_name, $orig_args) = ($1, $2, $3);
+ $class = "$4 $class" if $4;
+ ($pname = $func_name) =~ s/^($self->{Prefix})?/$self->{Packprefix}/;
+ my $clean_func_name;
+ ($clean_func_name = $func_name) =~ s/^$self->{Prefix}//;
+ $Full_func_name = "$self->{Packid}_$clean_func_name";
+ if ($Is_VMS) {
+ $Full_func_name = $SymSet->addsym($Full_func_name);
+ }
+
+ # Check for duplicate function definition
+ for my $tmp (@{ $self->{XSStack} }) {
+ next unless defined $tmp->{functions}{$Full_func_name};
+ Warn( $self, "Warning: duplicate function definition '$clean_func_name' detected");
+ last;
+ }
+ $self->{XSStack}->[$XSS_work_idx]{functions}{$Full_func_name}++;
+ %{ $self->{XsubAliases} } = ();
+ %{ $self->{XsubAliasValues} } = ();
+ %{ $self->{Interfaces} } = ();
+ @{ $self->{Attributes} } = ();
+ $self->{DoSetMagic} = 1;
+
+ $orig_args =~ s/\\\s*/ /g; # process line continuations
+ my @args;
+
+ my (@fake_INPUT_pre); # For length(s) generated variables
+ my (@fake_INPUT);
+ my $only_C_inlist_ref = {}; # Not in the signature of Perl function
+ if ($self->{argtypes} and $orig_args =~ /\S/) {
+ my $args = "$orig_args ,";
+ if ($args =~ /^( (??{ $C_arg }) , )* $ /x) {
+ @args = ($args =~ /\G ( (??{ $C_arg }) ) , /xg);
+ for ( @args ) {
+ s/^\s+//;
+ s/\s+$//;
+ my ($arg, $default) = ($_ =~ m/ ( [^=]* ) ( (?: = .* )? ) /x);
+ my ($pre, $len_name) = ($arg =~ /(.*?) \s*
+ \b ( \w+ | length\( \s*\w+\s* \) )
+ \s* $ /x);
+ next unless defined($pre) && length($pre);
+ my $out_type = '';
+ my $inout_var;
+ if ($self->{inout} and s/^(IN|IN_OUTLIST|OUTLIST|OUT|IN_OUT)\b\s*//) {
+ my $type = $1;
+ $out_type = $type if $type ne 'IN';
+ $arg =~ s/^(IN|IN_OUTLIST|OUTLIST|OUT|IN_OUT)\b\s*//;
+ $pre =~ s/^(IN|IN_OUTLIST|OUTLIST|OUT|IN_OUT)\b\s*//;
+ }
+ my $islength;
+ if ($len_name =~ /^length\( \s* (\w+) \s* \)\z/x) {
+ $len_name = "XSauto_length_of_$1";
+ $islength = 1;
+ die "Default value on length() argument: '$_'"
+ if length $default;
+ }
+ if (length $pre or $islength) { # Has a type
+ if ($islength) {
+ push @fake_INPUT_pre, $arg;
+ }
+ else {
+ push @fake_INPUT, $arg;
+ }
+ # warn "pushing '$arg'\n";
+ $self->{argtype_seen}->{$len_name}++;
+ $_ = "$len_name$default"; # Assigns to @args
+ }
+ $only_C_inlist_ref->{$_} = 1 if $out_type eq "OUTLIST" or $islength;
+ push @{ $outlist_ref }, $len_name if $out_type =~ /OUTLIST$/;
+ $self->{in_out}->{$len_name} = $out_type if $out_type;
+ }
+ }
+ else {
+ @args = split(/\s*,\s*/, $orig_args);
+ Warn( $self, "Warning: cannot parse argument list '$orig_args', fallback to split");
+ }
+ }
+ else {
+ @args = split(/\s*,\s*/, $orig_args);
+ for (@args) {
+ if ($self->{inout} and s/^(IN|IN_OUTLIST|OUTLIST|IN_OUT|OUT)\b\s*//) {
+ my $out_type = $1;
+ next if $out_type eq 'IN';
+ $only_C_inlist_ref->{$_} = 1 if $out_type eq "OUTLIST";
+ if ($out_type =~ /OUTLIST$/) {
+ push @{ $outlist_ref }, undef;
+ }
+ $self->{in_out}->{$_} = $out_type;
+ }
+ }
+ }
+ if (defined($class)) {
+ my $arg0 = ((defined($static) or $func_name eq 'new')
+ ? "CLASS" : "THIS");
+ unshift(@args, $arg0);
+ }
+ my $extra_args = 0;
+ my @args_num = ();
+ my $num_args = 0;
+ my $report_args = '';
+ my $ellipsis;
+ foreach my $i (0 .. $#args) {
+ if ($args[$i] =~ s/\.\.\.//) {
+ $ellipsis = 1;
+ if ($args[$i] eq '' && $i == $#args) {
+ $report_args .= ", ...";
+ pop(@args);
+ last;
+ }
+ }
+ if ($only_C_inlist_ref->{$args[$i]}) {
+ push @args_num, undef;
+ }
+ else {
+ push @args_num, ++$num_args;
+ $report_args .= ", $args[$i]";
+ }
+ if ($args[$i] =~ /^([^=]*[^\s=])\s*=\s*(.*)/s) {
+ $extra_args++;
+ $args[$i] = $1;
+ $self->{defaults}->{$args[$i]} = $2;
+ $self->{defaults}->{$args[$i]} =~ s/"/\\"/g;
+ }
+ $self->{proto_arg}->[$i+1] = '$';
+ }
+ my $min_args = $num_args - $extra_args;
+ $report_args =~ s/"/\\"/g;
+ $report_args =~ s/^,\s+//;
+ $self->{func_args} = assign_func_args($self, \@args, $class);
+ @{ $self->{args_match} }{@args} = @args_num;
+
+ my $PPCODE = grep(/^\s*PPCODE\s*:/, @{ $self->{line} });
+ my $CODE = grep(/^\s*CODE\s*:/, @{ $self->{line} });
+ # Detect CODE: blocks which use ST(n)= or XST_m*(n,v)
+ # to set explicit return values.
+ my $EXPLICIT_RETURN = ($CODE &&
+ ("@{ $self->{line} }" =~ /(\bST\s*\([^;]*=) | (\bXST_m\w+\s*\()/x ));
+
+ # The $ALIAS which follows is only explicitly called within the scope of
+ # process_file(). In principle, it ought to be a lexical, i.e., 'my
+ # $ALIAS' like the other nearby variables. However, implementing that
+ # change produced a slight difference in the resulting .c output in at
+ # least two distributions: B/BD/BDFOY/Crypt-Rijndael and
+ # G/GF/GFUJI/Hash-FieldHash. The difference is, arguably, an improvement
+ # in the resulting C code. Example:
+ # 388c388
+ # < GvNAME(CvGV(cv)),
+ # ---
+ # > "Crypt::Rijndael::encrypt",
+ # But at this point we're committed to generating the *same* C code that
+ # the current version of ParseXS.pm does. So we're declaring it as 'our'.
+ $ALIAS = grep(/^\s*ALIAS\s*:/, @{ $self->{line} });
+
+ my $INTERFACE = grep(/^\s*INTERFACE\s*:/, @{ $self->{line} });
+
+ $xsreturn = 1 if $EXPLICIT_RETURN;
+
+ $externC = $externC ? qq[extern "C"] : "";
+
+ # print function header
+ print Q(<<"EOF");
+#$externC
+#XS_EUPXS(XS_${Full_func_name}); /* prototype to pass -Wmissing-prototypes */
+#XS_EUPXS(XS_${Full_func_name})
+#[[
+# dVAR; dXSARGS;
+EOF
+ print Q(<<"EOF") if $ALIAS;
+# dXSI32;
+EOF
+ print Q(<<"EOF") if $INTERFACE;
+# dXSFUNCTION($self->{ret_type});
+EOF
+
+ $self->{cond} = set_cond($ellipsis, $min_args, $num_args);
+
+ print Q(<<"EOF") if $self->{except};
+# char errbuf[1024];
+# *errbuf = '\\0';
+EOF
+
+ if($self->{cond}) {
+ print Q(<<"EOF");
+# if ($self->{cond})
+# croak_xs_usage(cv, "$report_args");
+EOF
+ }
+ else {
+ # cv likely to be unused
+ print Q(<<"EOF");
+# PERL_UNUSED_VAR(cv); /* -W */
+EOF
+ }
+
+ #gcc -Wall: if an xsub has PPCODE is used
+ #it is possible none of ST, XSRETURN or XSprePUSH macros are used
+ #hence 'ax' (setup by dXSARGS) is unused
+ #XXX: could breakup the dXSARGS; into dSP;dMARK;dITEMS
+ #but such a move could break third-party extensions
+ print Q(<<"EOF") if $PPCODE;
+# PERL_UNUSED_VAR(ax); /* -Wall */
+EOF
+
+ print Q(<<"EOF") if $PPCODE;
+# SP -= items;
+EOF
+
+ # Now do a block of some sort.
+
+ $self->{condnum} = 0;
+ $self->{cond} = ''; # last CASE: conditional
+ push(@{ $self->{line} }, "$END:");
+ push(@{ $self->{line_no} }, $self->{line_no}->[-1]);
+ $_ = '';
+ check_conditional_preprocessor_statements();
+ while (@{ $self->{line} }) {
+
+ $self->CASE_handler($_) if $self->check_keyword("CASE");
+ print Q(<<"EOF");
+# $self->{except} [[
+EOF
+
+ # do initialization of input variables
+ $self->{thisdone} = 0;
+ $self->{retvaldone} = 0;
+ $self->{deferred} = "";
+ %{ $self->{arg_list} } = ();
+ $self->{gotRETVAL} = 0;
+ $self->INPUT_handler($_);
+ $self->process_keyword("INPUT|PREINIT|INTERFACE_MACRO|C_ARGS|ALIAS|ATTRS|PROTOTYPE|SCOPE|OVERLOAD");
+
+ print Q(<<"EOF") if $self->{ScopeThisXSUB};
+# ENTER;
+# [[
+EOF
+
+ if (!$self->{thisdone} && defined($class)) {
+ if (defined($static) or $func_name eq 'new') {
+ print "\tchar *";
+ $self->{var_types}->{"CLASS"} = "char *";
+ generate_init( {
+ type => "char *",
+ num => 1,
+ var => "CLASS",
+ printed_name => undef,
+ } );
+ }
+ else {
+ print "\t$class *";
+ $self->{var_types}->{"THIS"} = "$class *";
+ generate_init( {
+ type => "$class *",
+ num => 1,
+ var => "THIS",
+ printed_name => undef,
+ } );
+ }
+ }
+
+ # These are set if OUTPUT is found and/or CODE using RETVAL
+ $self->{have_OUTPUT} = $self->{have_CODE_with_RETVAL} = 0;
+
+ my ($wantRETVAL);
+ # do code
+ if (/^\s*NOT_IMPLEMENTED_YET/) {
+ print "\n\tPerl_croak(aTHX_ \"$pname: not implemented yet\");\n";
+ $_ = '';
+ }
+ else {
+ if ($self->{ret_type} ne "void") {
+ print "\t" . map_type($self, $self->{ret_type}, 'RETVAL') . ";\n"
+ if !$self->{retvaldone};
+ $self->{args_match}->{"RETVAL"} = 0;
+ $self->{var_types}->{"RETVAL"} = $self->{ret_type};
+ my $outputmap = $self->{typemap}->get_outputmap( ctype => $self->{ret_type} );
+ print "\tdXSTARG;\n"
+ if $self->{optimize} and $outputmap and $outputmap->targetable;
+ }
+
+ if (@fake_INPUT or @fake_INPUT_pre) {
+ unshift @{ $self->{line} }, @fake_INPUT_pre, @fake_INPUT, $_;
+ $_ = "";
+ $self->{processing_arg_with_types} = 1;
+ $self->INPUT_handler($_);
+ }
+ print $self->{deferred};
+
+ $self->process_keyword("INIT|ALIAS|ATTRS|PROTOTYPE|INTERFACE_MACRO|INTERFACE|C_ARGS|OVERLOAD");
+
+ if ($self->check_keyword("PPCODE")) {
+ $self->print_section();
+ $self->death("PPCODE must be last thing") if @{ $self->{line} };
+ print "\tLEAVE;\n" if $self->{ScopeThisXSUB};
+ print "\tPUTBACK;\n\treturn;\n";
+ }
+ elsif ($self->check_keyword("CODE")) {
+ my $consumed_code = $self->print_section();
+ if ($consumed_code =~ /\bRETVAL\b/) {
+ $self->{have_CODE_with_RETVAL} = 1;
+ }
+ }
+ elsif (defined($class) and $func_name eq "DESTROY") {
+ print "\n\t";
+ print "delete THIS;\n";
+ }
+ else {
+ print "\n\t";
+ if ($self->{ret_type} ne "void") {
+ print "RETVAL = ";
+ $wantRETVAL = 1;
+ }
+ if (defined($static)) {
+ if ($func_name eq 'new') {
+ $func_name = "$class";
+ }
+ else {
+ print "${class}::";
+ }
+ }
+ elsif (defined($class)) {
+ if ($func_name eq 'new') {
+ $func_name .= " $class";
+ }
+ else {
+ print "THIS->";
+ }
+ }
+ $func_name =~ s/^\Q$args{'s'}//
+ if exists $args{'s'};
+ $func_name = 'XSFUNCTION' if $self->{interface};
+ print "$func_name($self->{func_args});\n";
+ }
+ }
+
+ # do output variables
+ $self->{gotRETVAL} = 0; # 1 if RETVAL seen in OUTPUT section;
+ undef $self->{RETVAL_code} ; # code to set RETVAL (from OUTPUT section);
+ # $wantRETVAL set if 'RETVAL =' autogenerated
+ ($wantRETVAL, $self->{ret_type}) = (0, 'void') if $RETVAL_no_return;
+ undef %{ $self->{outargs} };
+
+ $self->process_keyword("POSTCALL|OUTPUT|ALIAS|ATTRS|PROTOTYPE|OVERLOAD");
+
+ # A CODE section with RETVAL, but no OUTPUT? FAIL!
+ if ($self->{have_CODE_with_RETVAL} and not $self->{have_OUTPUT} and $self->{ret_type} ne 'void') {
+ $self->Warn("Warning: Found a 'CODE' section which seems to be using 'RETVAL' but no 'OUTPUT' section.");
+ }
+
+ generate_output( {
+ type => $self->{var_types}->{$_},
+ num => $self->{args_match}->{$_},
+ var => $_,
+ do_setmagic => $self->{DoSetMagic},
+ do_push => undef,
+ } ) for grep $self->{in_out}->{$_} =~ /OUT$/, keys %{ $self->{in_out} };
+
+ my $prepush_done;
+ # all OUTPUT done, so now push the return value on the stack
+ if ($self->{gotRETVAL} && $self->{RETVAL_code}) {
+ print "\t$self->{RETVAL_code}\n";
+ }
+ elsif ($self->{gotRETVAL} || $wantRETVAL) {
+ my $outputmap = $self->{typemap}->get_outputmap( ctype => $self->{ret_type} );
+ my $t = $self->{optimize} && $outputmap && $outputmap->targetable;
+ # Although the '$var' declared in the next line is never explicitly
+ # used within this 'elsif' block, commenting it out leads to
+ # disaster, starting with the first 'eval qq' inside the 'elsif' block
+ # below.
+ # It appears that this is related to the fact that at this point the
+ # value of $t is a reference to an array whose [2] element includes
+ # '$var' as a substring:
+ # <i> <> <(IV)$var>
+ my $var = 'RETVAL';
+ my $type = $self->{ret_type};
+
+ if ($t and not $t->{with_size} and $t->{type} eq 'p') {
+ # PUSHp corresponds to setpvn. Treat setpv directly
+ my $what = eval qq("$t->{what}");
+ warn $@ if $@;
+
+ print "\tsv_setpv(TARG, $what); XSprePUSH; PUSHTARG;\n";
+ $prepush_done = 1;
+ }
+ elsif ($t) {
+ my $what = eval qq("$t->{what}");
+ warn $@ if $@;
+
+ my $tsize = $t->{what_size};
+ $tsize = '' unless defined $tsize;
+ $tsize = eval qq("$tsize");
+ warn $@ if $@;
+ print "\tXSprePUSH; PUSH$t->{type}($what$tsize);\n";
+ $prepush_done = 1;
+ }
+ else {
+ # RETVAL almost never needs SvSETMAGIC()
+ generate_output( {
+ type => $self->{ret_type},
+ num => 0,
+ var => 'RETVAL',
+ do_setmagic => 0,
+ do_push => undef,
+ } );
+ }
+ }
+
+ $xsreturn = 1 if $self->{ret_type} ne "void";
+ my $num = $xsreturn;
+ my $c = @{ $outlist_ref };
+ print "\tXSprePUSH;" if $c and not $prepush_done;
+ print "\tEXTEND(SP,$c);\n" if $c;
+ $xsreturn += $c;
+ generate_output( {
+ type => $self->{var_types}->{$_},
+ num => $num++,
+ var => $_,
+ do_setmagic => 0,
+ do_push => 1,
+ } ) for @{ $outlist_ref };
+
+ # do cleanup
+ $self->process_keyword("CLEANUP|ALIAS|ATTRS|PROTOTYPE|OVERLOAD");
+
+ print Q(<<"EOF") if $self->{ScopeThisXSUB};
+# ]]
+EOF
+ print Q(<<"EOF") if $self->{ScopeThisXSUB} and not $PPCODE;
+# LEAVE;
+EOF
+
+ # print function trailer
+ print Q(<<"EOF");
+# ]]
+EOF
+ print Q(<<"EOF") if $self->{except};
+# BEGHANDLERS
+# CATCHALL
+# sprintf(errbuf, "%s: %s\\tpropagated", Xname, Xreason);
+# ENDHANDLERS
+EOF
+ if ($self->check_keyword("CASE")) {
+ $self->blurt("Error: No 'CASE:' at top of function")
+ unless $self->{condnum};
+ $_ = "CASE: $_"; # Restore CASE: label
+ next;
+ }
+ last if $_ eq "$END:";
+ $self->death(/^$self->{BLOCK_re}/o ? "Misplaced '$1:'" : "Junk at end of function ($_)");
+ }
+
+ print Q(<<"EOF") if $self->{except};
+# if (errbuf[0])
+# Perl_croak(aTHX_ errbuf);
+EOF
+
+ if ($xsreturn) {
+ print Q(<<"EOF") unless $PPCODE;
+# XSRETURN($xsreturn);
+EOF
+ }
+ else {
+ print Q(<<"EOF") unless $PPCODE;
+# XSRETURN_EMPTY;
+EOF
+ }
+
+ print Q(<<"EOF");
+#]]
+#
+EOF
+
+ $self->{newXS} = "newXS";
+ $self->{proto} = "";
+
+ # Build the prototype string for the xsub
+ if ($self->{ProtoThisXSUB}) {
+ $self->{newXS} = "newXSproto_portable";
+
+ if ($self->{ProtoThisXSUB} eq 2) {
+ # User has specified empty prototype
+ }
+ elsif ($self->{ProtoThisXSUB} eq 1) {
+ my $s = ';';
+ if ($min_args < $num_args) {
+ $s = '';
+ $self->{proto_arg}->[$min_args] .= ";";
+ }
+ push @{ $self->{proto_arg} }, "$s\@"
+ if $ellipsis;
+
+ $self->{proto} = join ("", grep defined, @{ $self->{proto_arg} } );
+ }
+ else {
+ # User has specified a prototype
+ $self->{proto} = $self->{ProtoThisXSUB};
+ }
+ $self->{proto} = qq{, "$self->{proto}"};
+ }
+
+ if (%{ $self->{XsubAliases} }) {
+ $self->{XsubAliases}->{$pname} = 0
+ unless defined $self->{XsubAliases}->{$pname};
+ while ( my ($xname, $value) = each %{ $self->{XsubAliases} }) {
+ push(@{ $self->{InitFileCode} }, Q(<<"EOF"));
+# cv = $self->{newXS}(\"$xname\", XS_$Full_func_name, file$self->{proto});
+# XSANY.any_i32 = $value;
+EOF
+ }
+ }
+ elsif (@{ $self->{Attributes} }) {
+ push(@{ $self->{InitFileCode} }, Q(<<"EOF"));
+# cv = $self->{newXS}(\"$pname\", XS_$Full_func_name, file$self->{proto});
+# apply_attrs_string("$Package", cv, "@{ $self->{Attributes} }", 0);
+EOF
+ }
+ elsif ($self->{interface}) {
+ while ( my ($yname, $value) = each %{ $self->{Interfaces} }) {
+ $yname = "$Package\::$yname" unless $yname =~ /::/;
+ push(@{ $self->{InitFileCode} }, Q(<<"EOF"));
+# cv = $self->{newXS}(\"$yname\", XS_$Full_func_name, file$self->{proto});
+# $self->{interface_macro_set}(cv,$value);
+EOF
+ }
+ }
+ elsif($self->{newXS} eq 'newXS'){ # work around P5NCI's empty newXS macro
+ push(@{ $self->{InitFileCode} },
+ " $self->{newXS}(\"$pname\", XS_$Full_func_name, file$self->{proto});\n");
+ }
+ else {
+ push(@{ $self->{InitFileCode} },
+ " (void)$self->{newXS}(\"$pname\", XS_$Full_func_name, file$self->{proto});\n");
+ }
+ } # END 'PARAGRAPH' 'while' loop
+
+ if ($self->{Overload}) { # make it findable with fetchmethod
+ print Q(<<"EOF");
+#XS_EUPXS(XS_$self->{Packid}_nil); /* prototype to pass -Wmissing-prototypes */
+#XS_EUPXS(XS_$self->{Packid}_nil)
+#{
+# dXSARGS;
+# XSRETURN_EMPTY;
+#}
+#
+EOF
+ unshift(@{ $self->{InitFileCode} }, <<"MAKE_FETCHMETHOD_WORK");
+ /* Making a sub named "${Package}::()" allows the package */
+ /* to be findable via fetchmethod(), and causes */
+ /* overload::Overloaded("${Package}") to return true. */
+ (void)$self->{newXS}("${Package}::()", XS_$self->{Packid}_nil, file$self->{proto});
+MAKE_FETCHMETHOD_WORK
+ }
+
+ # print initialization routine
+
+ print Q(<<"EOF");
+##ifdef __cplusplus
+#extern "C"
+##endif
+EOF
+
+ print Q(<<"EOF");
+#XS_EXTERNAL(boot_$self->{Module_cname}); /* prototype to pass -Wmissing-prototypes */
+#XS_EXTERNAL(boot_$self->{Module_cname})
+EOF
+
+ print Q(<<"EOF");
+#[[
+# dVAR; dXSARGS;
+EOF
+
+ #Under 5.8.x and lower, newXS is declared in proto.h as expecting a non-const
+ #file name argument. If the wrong qualifier is used, it causes breakage with
+ #C++ compilers and warnings with recent gcc.
+ #-Wall: if there is no $Full_func_name there are no xsubs in this .xs
+ #so 'file' is unused
+ print Q(<<"EOF") if $Full_func_name;
+##if (PERL_REVISION == 5 && PERL_VERSION < 9)
+# char* file = __FILE__;
+##else
+# const char* file = __FILE__;
+##endif
+EOF
+
+ print Q("#\n");
+
+ print Q(<<"EOF");
+# PERL_UNUSED_VAR(cv); /* -W */
+# PERL_UNUSED_VAR(items); /* -W */
+##ifdef XS_APIVERSION_BOOTCHECK
+# XS_APIVERSION_BOOTCHECK;
+##endif
+EOF
+
+ print Q(<<"EOF") if $self->{WantVersionChk};
+# XS_VERSION_BOOTCHECK;
+#
+EOF
+
+ print Q(<<"EOF") if defined $self->{xsubaliases} or defined $self->{interfaces};
+# {
+# CV * cv;
+#
+EOF
+
+ print Q(<<"EOF") if ($self->{Overload});
+# /* register the overloading (type 'A') magic */
+# PL_amagic_generation++;
+# /* The magic for overload gets a GV* via gv_fetchmeth as */
+# /* mentioned above, and looks in the SV* slot of it for */
+# /* the "fallback" status. */
+# sv_setsv(
+# get_sv( "${Package}::()", TRUE ),
+# $self->{Fallback}
+# );
+EOF
+
+ print @{ $self->{InitFileCode} };
+
+ print Q(<<"EOF") if defined $self->{xsubaliases} or defined $self->{interfaces};
+# }
+EOF
+
+ if (@{ $BootCode_ref }) {
+ print "\n /* Initialisation Section */\n\n";
+ @{ $self->{line} } = @{ $BootCode_ref };
+ $self->print_section();
+ print "\n /* End of Initialisation Section */\n\n";
+ }
+
+ print Q(<<'EOF');
+##if (PERL_REVISION == 5 && PERL_VERSION >= 9)
+# if (PL_unitcheckav)
+# call_list(PL_scopestack_ix, PL_unitcheckav);
+##endif
+EOF
+
+ print Q(<<"EOF");
+# XSRETURN_YES;
+#]]
+#
+EOF
+
+ warn("Please specify prototyping behavior for $self->{filename} (see perlxs manual)\n")
+ unless $self->{ProtoUsed};
+
+ chdir($orig_cwd);
+ select($orig_fh);
+ untie *PSEUDO_STDOUT if tied *PSEUDO_STDOUT;
+ close $self->{FH};
+
+ return 1;
+}
+
+sub report_error_count { $self->{errors} }
+
+# Input: ($self, $_, @{ $self->{line} }) == unparsed input.
+# Output: ($_, @{ $self->{line} }) == (rest of line, following lines).
+# Return: the matched keyword if found, otherwise 0
+sub check_keyword {
+ my $self = shift;
+ $_ = shift(@{ $self->{line} }) while !/\S/ && @{ $self->{line} };
+ s/^(\s*)($_[0])\s*:\s*(?:#.*)?/$1/s && $2;
+}
+
+sub print_section {
+ my $self = shift;
+
+ # the "do" is required for right semantics
+ do { $_ = shift(@{ $self->{line} }) } while !/\S/ && @{ $self->{line} };
+
+ my $consumed_code = '';
+
+ print("#line ", $self->{line_no}->[@{ $self->{line_no} } - @{ $self->{line} } -1], " \"",
+ escape_file_for_line_directive($self->{filepathname}), "\"\n")
+ if $self->{WantLineNumbers} && !/^\s*#\s*line\b/ && !/^#if XSubPPtmp/;
+ for (; defined($_) && !/^$self->{BLOCK_re}/o; $_ = shift(@{ $self->{line} })) {
+ print "$_\n";
+ $consumed_code .= "$_\n";
+ }
+ print 'ExtUtils::ParseXS::CountLines'->end_marker, "\n" if $self->{WantLineNumbers};
+
+ return $consumed_code;
+}
+
+sub merge_section {
+ my $self = shift;
+ my $in = '';
+
+ while (!/\S/ && @{ $self->{line} }) {
+ $_ = shift(@{ $self->{line} });
+ }
+
+ for (; defined($_) && !/^$self->{BLOCK_re}/o; $_ = shift(@{ $self->{line} })) {
+ $in .= "$_\n";
+ }
+ chomp $in;
+ return $in;
+}
+
+sub process_keyword {
+ my($self, $pattern) = @_;
+
+ while (my $kwd = $self->check_keyword($pattern)) {
+ my $method = $kwd . "_handler";
+ $self->$method($_);
+ }
+}
+
+sub CASE_handler {
+ my $self = shift;
+ $_ = shift;
+ $self->blurt("Error: 'CASE:' after unconditional 'CASE:'")
+ if $self->{condnum} && $self->{cond} eq '';
+ $self->{cond} = $_;
+ trim_whitespace($self->{cond});
+ print " ", ($self->{condnum}++ ? " else" : ""), ($self->{cond} ? " if ($self->{cond})\n" : "\n");
+ $_ = '';
+}
+
+sub INPUT_handler {
+ my $self = shift;
+ $_ = shift;
+ for (; !/^$self->{BLOCK_re}/o; $_ = shift(@{ $self->{line} })) {
+ last if /^\s*NOT_IMPLEMENTED_YET/;
+ next unless /\S/; # skip blank lines
+
+ trim_whitespace($_);
+ my $ln = $_;
+
+ # remove trailing semicolon if no initialisation
+ s/\s*;$//g unless /[=;+].*\S/;
+
+ # Process the length(foo) declarations
+ if (s/^([^=]*)\blength\(\s*(\w+)\s*\)\s*$/$1 XSauto_length_of_$2=NO_INIT/x) {
+ print "\tSTRLEN\tSTRLEN_length_of_$2;\n";
+ $self->{lengthof}->{$2} = undef;
+ $self->{deferred} .= "\n\tXSauto_length_of_$2 = STRLEN_length_of_$2;\n";
+ }
+
+ # check for optional initialisation code
+ my $var_init = '';
+ $var_init = $1 if s/\s*([=;+].*)$//s;
+ $var_init =~ s/"/\\"/g;
+ # *sigh* It's valid to supply explicit input typemaps in the argument list...
+ my $is_overridden_typemap = $var_init =~ /ST\s*\(|\$arg\b/;
+
+ s/\s+/ /g;
+ my ($var_type, $var_addr, $var_name) = /^(.*?[^&\s])\s*(\&?)\s*\b(\w+)$/s
+ or $self->blurt("Error: invalid argument declaration '$ln'"), next;
+
+ # Check for duplicate definitions
+ $self->blurt("Error: duplicate definition of argument '$var_name' ignored"), next
+ if $self->{arg_list}->{$var_name}++
+ or defined $self->{argtype_seen}->{$var_name} and not $self->{processing_arg_with_types};
+
+ $self->{thisdone} |= $var_name eq "THIS";
+ $self->{retvaldone} |= $var_name eq "RETVAL";
+ $self->{var_types}->{$var_name} = $var_type;
+ # XXXX This check is a safeguard against the unfinished conversion of
+ # generate_init(). When generate_init() is fixed,
+ # one can use 2-args map_type() unconditionally.
+ my $printed_name;
+ if ($var_type =~ / \( \s* \* \s* \) /x) {
+ # Function pointers are not yet supported with output_init()!
+ print "\t" . map_type($self, $var_type, $var_name);
+ $printed_name = 1;
+ }
+ else {
+ print "\t" . map_type($self, $var_type, undef);
+ $printed_name = 0;
+ }
+ $self->{var_num} = $self->{args_match}->{$var_name};
+
+ if ($self->{var_num}) {
+ my $typemap = $self->{typemap}->get_typemap(ctype => $var_type);
+ $self->report_typemap_failure($self->{typemap}, $var_type, "death")
+ if not $typemap and not $is_overridden_typemap;
+ $self->{proto_arg}->[$self->{var_num}] = ($typemap && $typemap->proto) || "\$";
+ }
+ $self->{func_args} =~ s/\b($var_name)\b/&$1/ if $var_addr;
+ if ($var_init =~ /^[=;]\s*NO_INIT\s*;?\s*$/
+ or $self->{in_out}->{$var_name} and $self->{in_out}->{$var_name} =~ /^OUT/
+ and $var_init !~ /\S/) {
+ if ($printed_name) {
+ print ";\n";
+ }
+ else {
+ print "\t$var_name;\n";
+ }
+ }
+ elsif ($var_init =~ /\S/) {
+ output_init( {
+ type => $var_type,
+ num => $self->{var_num},
+ var => $var_name,
+ init => $var_init,
+ printed_name => $printed_name,
+ } );
+ }
+ elsif ($self->{var_num}) {
+ generate_init( {
+ type => $var_type,
+ num => $self->{var_num},
+ var => $var_name,
+ printed_name => $printed_name,
+ } );
+ }
+ else {
+ print ";\n";
+ }
+ }
+}
+
+sub OUTPUT_handler {
+ my $self = shift;
+ $self->{have_OUTPUT} = 1;
+
+ $_ = shift;
+ for (; !/^$self->{BLOCK_re}/o; $_ = shift(@{ $self->{line} })) {
+ next unless /\S/;
+ if (/^\s*SETMAGIC\s*:\s*(ENABLE|DISABLE)\s*/) {
+ $self->{DoSetMagic} = ($1 eq "ENABLE" ? 1 : 0);
+ next;
+ }
+ my ($outarg, $outcode) = /^\s*(\S+)\s*(.*?)\s*$/s;
+ $self->blurt("Error: duplicate OUTPUT argument '$outarg' ignored"), next
+ if $self->{outargs}->{$outarg}++;
+ if (!$self->{gotRETVAL} and $outarg eq 'RETVAL') {
+ # deal with RETVAL last
+ $self->{RETVAL_code} = $outcode;
+ $self->{gotRETVAL} = 1;
+ next;
+ }
+ $self->blurt("Error: OUTPUT $outarg not an argument"), next
+ unless defined($self->{args_match}->{$outarg});
+ $self->blurt("Error: No input definition for OUTPUT argument '$outarg' - ignored"), next
+ unless defined $self->{var_types}->{$outarg};
+ $self->{var_num} = $self->{args_match}->{$outarg};
+ if ($outcode) {
+ print "\t$outcode\n";
+ print "\tSvSETMAGIC(ST(" , $self->{var_num} - 1 , "));\n" if $self->{DoSetMagic};
+ }
+ else {
+ generate_output( {
+ type => $self->{var_types}->{$outarg},
+ num => $self->{var_num},
+ var => $outarg,
+ do_setmagic => $self->{DoSetMagic},
+ do_push => undef,
+ } );
+ }
+ delete $self->{in_out}->{$outarg} # No need to auto-OUTPUT
+ if exists $self->{in_out}->{$outarg} and $self->{in_out}->{$outarg} =~ /OUT$/;
+ }
+}
+
+sub C_ARGS_handler {
+ my $self = shift;
+ $_ = shift;
+ my $in = $self->merge_section();
+
+ trim_whitespace($in);
+ $self->{func_args} = $in;
+}
+
+sub INTERFACE_MACRO_handler {
+ my $self = shift;
+ $_ = shift;
+ my $in = $self->merge_section();
+
+ trim_whitespace($in);
+ if ($in =~ /\s/) { # two
+ ($self->{interface_macro}, $self->{interface_macro_set}) = split ' ', $in;
+ }
+ else {
+ $self->{interface_macro} = $in;
+ $self->{interface_macro_set} = 'UNKNOWN_CVT'; # catch later
+ }
+ $self->{interface} = 1; # local
+ $self->{interfaces} = 1; # global
+}
+
+sub INTERFACE_handler {
+ my $self = shift;
+ $_ = shift;
+ my $in = $self->merge_section();
+
+ trim_whitespace($in);
+
+ foreach (split /[\s,]+/, $in) {
+ my $iface_name = $_;
+ $iface_name =~ s/^$self->{Prefix}//;
+ $self->{Interfaces}->{$iface_name} = $_;
+ }
+ print Q(<<"EOF");
+# XSFUNCTION = $self->{interface_macro}($self->{ret_type},cv,XSANY.any_dptr);
+EOF
+ $self->{interface} = 1; # local
+ $self->{interfaces} = 1; # global
+}
+
+sub CLEANUP_handler {
+ my $self = shift;
+ $self->print_section();
+}
+
+sub PREINIT_handler {
+ my $self = shift;
+ $self->print_section();
+}
+
+sub POSTCALL_handler {
+ my $self = shift;
+ $self->print_section();
+}
+
+sub INIT_handler {
+ my $self = shift;
+ $self->print_section();
+}
+
+sub get_aliases {
+ my $self = shift;
+ my ($line) = @_;
+ my ($orig) = $line;
+
+ # Parse alias definitions
+ # format is
+ # alias = value alias = value ...
+
+ while ($line =~ s/^\s*([\w:]+)\s*=\s*(\w+)\s*//) {
+ my ($alias, $value) = ($1, $2);
+ my $orig_alias = $alias;
+
+ # check for optional package definition in the alias
+ $alias = $self->{Packprefix} . $alias if $alias !~ /::/;
+
+ # check for duplicate alias name & duplicate value
+ Warn( $self, "Warning: Ignoring duplicate alias '$orig_alias'")
+ if defined $self->{XsubAliases}->{$alias};
+
+ Warn( $self, "Warning: Aliases '$orig_alias' and '$self->{XsubAliasValues}->{$value}' have identical values")
+ if $self->{XsubAliasValues}->{$value};
+
+ $self->{xsubaliases} = 1;
+ $self->{XsubAliases}->{$alias} = $value;
+ $self->{XsubAliasValues}->{$value} = $orig_alias;
+ }
+
+ blurt( $self, "Error: Cannot parse ALIAS definitions from '$orig'")
+ if $line;
+}
+
+sub ATTRS_handler {
+ my $self = shift;
+ $_ = shift;
+
+ for (; !/^$self->{BLOCK_re}/o; $_ = shift(@{ $self->{line} })) {
+ next unless /\S/;
+ trim_whitespace($_);
+ push @{ $self->{Attributes} }, $_;
+ }
+}
+
+sub ALIAS_handler {
+ my $self = shift;
+ $_ = shift;
+
+ for (; !/^$self->{BLOCK_re}/o; $_ = shift(@{ $self->{line} })) {
+ next unless /\S/;
+ trim_whitespace($_);
+ $self->get_aliases($_) if $_;
+ }
+}
+
+sub OVERLOAD_handler {
+ my $self = shift;
+ $_ = shift;
+
+ for (; !/^$self->{BLOCK_re}/o; $_ = shift(@{ $self->{line} })) {
+ next unless /\S/;
+ trim_whitespace($_);
+ while ( s/^\s*([\w:"\\)\+\-\*\/\%\<\>\.\&\|\^\!\~\{\}\=]+)\s*//) {
+ $self->{Overload} = 1 unless $self->{Overload};
+ my $overload = "$Package\::(".$1;
+ push(@{ $self->{InitFileCode} },
+ " (void)$self->{newXS}(\"$overload\", XS_$Full_func_name, file$self->{proto});\n");
+ }
+ }
+}
+
+sub FALLBACK_handler {
+ my $self = shift;
+ $_ = shift;
+
+ # the rest of the current line should contain either TRUE,
+ # FALSE or UNDEF
+
+ trim_whitespace($_);
+ my %map = (
+ TRUE => "&PL_sv_yes", 1 => "&PL_sv_yes",
+ FALSE => "&PL_sv_no", 0 => "&PL_sv_no",
+ UNDEF => "&PL_sv_undef",
+ );
+
+ # check for valid FALLBACK value
+ $self->death("Error: FALLBACK: TRUE/FALSE/UNDEF") unless exists $map{uc $_};
+
+ $self->{Fallback} = $map{uc $_};
+}
+
+
+sub REQUIRE_handler {
+ my $self = shift;
+ # the rest of the current line should contain a version number
+ my $Ver = shift;
+
+ trim_whitespace($Ver);
+
+ $self->death("Error: REQUIRE expects a version number")
+ unless $Ver;
+
+ # check that the version number is of the form n.n
+ $self->death("Error: REQUIRE: expected a number, got '$Ver'")
+ unless $Ver =~ /^\d+(\.\d*)?/;
+
+ $self->death("Error: xsubpp $Ver (or better) required--this is only $VERSION.")
+ unless $VERSION >= $Ver;
+}
+
+sub VERSIONCHECK_handler {
+ my $self = shift;
+ $_ = shift;
+
+ # the rest of the current line should contain either ENABLE or
+ # DISABLE
+
+ trim_whitespace($_);
+
+ # check for ENABLE/DISABLE
+ $self->death("Error: VERSIONCHECK: ENABLE/DISABLE")
+ unless /^(ENABLE|DISABLE)/i;
+
+ $self->{WantVersionChk} = 1 if $1 eq 'ENABLE';
+ $self->{WantVersionChk} = 0 if $1 eq 'DISABLE';
+
+}
+
+sub PROTOTYPE_handler {
+ my $self = shift;
+ $_ = shift;
+
+ my $specified;
+
+ $self->death("Error: Only 1 PROTOTYPE definition allowed per xsub")
+ if $self->{proto_in_this_xsub}++;
+
+ for (; !/^$self->{BLOCK_re}/o; $_ = shift(@{ $self->{line} })) {
+ next unless /\S/;
+ $specified = 1;
+ trim_whitespace($_);
+ if ($_ eq 'DISABLE') {
+ $self->{ProtoThisXSUB} = 0;
+ }
+ elsif ($_ eq 'ENABLE') {
+ $self->{ProtoThisXSUB} = 1;
+ }
+ else {
+ # remove any whitespace
+ s/\s+//g;
+ $self->death("Error: Invalid prototype '$_'")
+ unless valid_proto_string($_);
+ $self->{ProtoThisXSUB} = C_string($_);
+ }
+ }
+
+ # If no prototype specified, then assume empty prototype ""
+ $self->{ProtoThisXSUB} = 2 unless $specified;
+
+ $self->{ProtoUsed} = 1;
+}
+
+sub SCOPE_handler {
+ my $self = shift;
+ $_ = shift;
+
+ $self->death("Error: Only 1 SCOPE declaration allowed per xsub")
+ if $self->{scope_in_this_xsub}++;
+
+ trim_whitespace($_);
+ $self->death("Error: SCOPE: ENABLE/DISABLE")
+ unless /^(ENABLE|DISABLE)\b/i;
+ $self->{ScopeThisXSUB} = ( uc($1) eq 'ENABLE' );
+}
+
+sub PROTOTYPES_handler {
+ my $self = shift;
+ $_ = shift;
+
+ # the rest of the current line should contain either ENABLE or
+ # DISABLE
+
+ trim_whitespace($_);
+
+ # check for ENABLE/DISABLE
+ $self->death("Error: PROTOTYPES: ENABLE/DISABLE")
+ unless /^(ENABLE|DISABLE)/i;
+
+ $self->{WantPrototypes} = 1 if $1 eq 'ENABLE';
+ $self->{WantPrototypes} = 0 if $1 eq 'DISABLE';
+ $self->{ProtoUsed} = 1;
+}
+
+sub EXPORT_XSUB_SYMBOLS_handler {
+ my $self = shift;
+ $_ = shift;
+
+ # the rest of the current line should contain either ENABLE or
+ # DISABLE
+
+ trim_whitespace($_);
+
+ # check for ENABLE/DISABLE
+ $self->death("Error: EXPORT_XSUB_SYMBOLS: ENABLE/DISABLE")
+ unless /^(ENABLE|DISABLE)/i;
+
+ my $xs_impl = $1 eq 'ENABLE' ? 'XS_EXTERNAL' : 'XS_INTERNAL';
+
+ print Q(<<"EOF");
+##undef XS_EUPXS
+##if defined(PERL_EUPXS_ALWAYS_EXPORT)
+## define XS_EUPXS(name) XS_EXTERNAL(name)
+##elif defined(PERL_EUPXS_NEVER_EXPORT)
+## define XS_EUPXS(name) XS_INTERNAL(name)
+##else
+## define XS_EUPXS(name) $xs_impl(name)
+##endif
+EOF
+}
+
+
+sub PushXSStack {
+ my $self = shift;
+ my %args = @_;
+ # Save the current file context.
+ push(@{ $self->{XSStack} }, {
+ type => 'file',
+ LastLine => $self->{lastline},
+ LastLineNo => $self->{lastline_no},
+ Line => $self->{line},
+ LineNo => $self->{line_no},
+ Filename => $self->{filename},
+ Filepathname => $self->{filepathname},
+ Handle => $self->{FH},
+ IsPipe => scalar($self->{filename} =~ /\|\s*$/),
+ %args,
+ });
+
+}
+
+sub INCLUDE_handler {
+ my $self = shift;
+ $_ = shift;
+ # the rest of the current line should contain a valid filename
+
+ trim_whitespace($_);
+
+ $self->death("INCLUDE: filename missing")
+ unless $_;
+
+ $self->death("INCLUDE: output pipe is illegal")
+ if /^\s*\|/;
+
+ # simple minded recursion detector
+ $self->death("INCLUDE loop detected")
+ if $self->{IncludedFiles}->{$_};
+
+ ++$self->{IncludedFiles}->{$_} unless /\|\s*$/;
+
+ if (/\|\s*$/ && /^\s*perl\s/) {
+ Warn( $self, "The INCLUDE directive with a command is discouraged." .
+ " Use INCLUDE_COMMAND instead! In particular using 'perl'" .
+ " in an 'INCLUDE: ... |' directive is not guaranteed to pick" .
+ " up the correct perl. The INCLUDE_COMMAND directive allows" .
+ " the use of \$^X as the currently running perl, see" .
+ " 'perldoc perlxs' for details.");
+ }
+
+ $self->PushXSStack();
+
+ $self->{FH} = Symbol::gensym();
+
+ # open the new file
+ open($self->{FH}, $_) or $self->death("Cannot open '$_': $!");
+
+ print Q(<<"EOF");
+#
+#/* INCLUDE: Including '$_' from '$self->{filename}' */
+#
+EOF
+
+ $self->{filename} = $_;
+ $self->{filepathname} = ( $^O =~ /^mswin/i )
+ ? qq($self->{dir}/$self->{filename}) # See CPAN RT #61908: gcc doesn't like backslashes on win32?
+ : File::Spec->catfile($self->{dir}, $self->{filename});
+
+ # Prime the pump by reading the first
+ # non-blank line
+
+ # skip leading blank lines
+ while (readline($self->{FH})) {
+ last unless /^\s*$/;
+ }
+
+ $self->{lastline} = $_;
+ $self->{lastline_no} = $.;
+}
+
+sub QuoteArgs {
+ my $cmd = shift;
+ my @args = split /\s+/, $cmd;
+ $cmd = shift @args;
+ for (@args) {
+ $_ = q(").$_.q(") if !/^\"/ && length($_) > 0;
+ }
+ return join (' ', ($cmd, @args));
+}
+
+sub INCLUDE_COMMAND_handler {
+ my $self = shift;
+ $_ = shift;
+ # the rest of the current line should contain a valid command
+
+ trim_whitespace($_);
+
+ $_ = QuoteArgs($_) if $^O eq 'VMS';
+
+ $self->death("INCLUDE_COMMAND: command missing")
+ unless $_;
+
+ $self->death("INCLUDE_COMMAND: pipes are illegal")
+ if /^\s*\|/ or /\|\s*$/;
+
+ $self->PushXSStack( IsPipe => 1 );
+
+ $self->{FH} = Symbol::gensym();
+
+ # If $^X is used in INCLUDE_COMMAND, we know it's supposed to be
+ # the same perl interpreter as we're currently running
+ s/^\s*\$\^X/$^X/;
+
+ # open the new file
+ open ($self->{FH}, "-|", $_)
+ or $self->death( $self, "Cannot run command '$_' to include its output: $!");
+
+ print Q(<<"EOF");
+#
+#/* INCLUDE_COMMAND: Including output of '$_' from '$self->{filename}' */
+#
+EOF
+
+ $self->{filename} = $_;
+ $self->{filepathname} = $self->{filename};
+ #$self->{filepathname} =~ s/\"/\\"/g; # Fails? See CPAN RT #53938: MinGW Broken after 2.21
+ $self->{filepathname} =~ s/\\/\\\\/g; # Works according to reporter of #53938
+
+ # Prime the pump by reading the first
+ # non-blank line
+
+ # skip leading blank lines
+ while (readline($self->{FH})) {
+ last unless /^\s*$/;
+ }
+
+ $self->{lastline} = $_;
+ $self->{lastline_no} = $.;
+}
+
+sub PopFile {
+ my $self = shift;
+
+ return 0 unless $self->{XSStack}->[-1]{type} eq 'file';
+
+ my $data = pop @{ $self->{XSStack} };
+ my $ThisFile = $self->{filename};
+ my $isPipe = $data->{IsPipe};
+
+ --$self->{IncludedFiles}->{$self->{filename}}
+ unless $isPipe;
+
+ close $self->{FH};
+
+ $self->{FH} = $data->{Handle};
+ # $filename is the leafname, which for some reason isused for diagnostic
+ # messages, whereas $filepathname is the full pathname, and is used for
+ # #line directives.
+ $self->{filename} = $data->{Filename};
+ $self->{filepathname} = $data->{Filepathname};
+ $self->{lastline} = $data->{LastLine};
+ $self->{lastline_no} = $data->{LastLineNo};
+ @{ $self->{line} } = @{ $data->{Line} };
+ @{ $self->{line_no} } = @{ $data->{LineNo} };
+
+ if ($isPipe and $? ) {
+ --$self->{lastline_no};
+ print STDERR "Error reading from pipe '$ThisFile': $! in $self->{filename}, line $self->{lastline_no}\n" ;
+ exit 1;
+ }
+
+ print Q(<<"EOF");
+#
+#/* INCLUDE: Returning to '$self->{filename}' from '$ThisFile' */
+#
+EOF
+
+ return 1;
+}
+
+sub Q {
+ my($text) = @_;
+ $text =~ s/^#//gm;
+ $text =~ s/\[\[/{/g;
+ $text =~ s/\]\]/}/g;
+ $text;
+}
+
+# Read next xsub into @{ $self->{line} } from ($lastline, readline($self->{FH})).
+sub fetch_para {
+ my $self = shift;
+
+ # parse paragraph
+ $self->death("Error: Unterminated '#if/#ifdef/#ifndef'")
+ if !defined $self->{lastline} && $self->{XSStack}->[-1]{type} eq 'if';
+ @{ $self->{line} } = ();
+ @{ $self->{line_no} } = ();
+ return $self->PopFile() if !defined $self->{lastline};
+
+ if ($self->{lastline} =~
+ /^MODULE\s*=\s*([\w:]+)(?:\s+PACKAGE\s*=\s*([\w:]+))?(?:\s+PREFIX\s*=\s*(\S+))?\s*$/) {
+ my $Module = $1;
+ $Package = defined($2) ? $2 : ''; # keep -w happy
+ $self->{Prefix} = defined($3) ? $3 : ''; # keep -w happy
+ $self->{Prefix} = quotemeta $self->{Prefix};
+ ($self->{Module_cname} = $Module) =~ s/\W/_/g;
+ ($self->{Packid} = $Package) =~ tr/:/_/;
+ $self->{Packprefix} = $Package;
+ $self->{Packprefix} .= "::" if $self->{Packprefix} ne "";
+ $self->{lastline} = "";
+ }
+
+ for (;;) {
+ # Skip embedded PODs
+ while ($self->{lastline} =~ /^=/) {
+ while ($self->{lastline} = readline($self->{FH})) {
+ last if ($self->{lastline} =~ /^=cut\s*$/);
+ }
+ $self->death("Error: Unterminated pod") unless $self->{lastline};
+ $self->{lastline} = readline($self->{FH});
+ chomp $self->{lastline};
+ $self->{lastline} =~ s/^\s+$//;
+ }
+
+ # This chunk of code strips out (and parses) embedded TYPEMAP blocks
+ # which support a HEREdoc-alike block syntax.
+ # This is special cased from the usual paragraph-handler logic
+ # due to the HEREdoc-ish syntax.
+ if ($self->{lastline} =~ /^TYPEMAP\s*:\s*<<\s*(?:(["'])(.+?)\1|([^\s'"]+))\s*;?\s*$/) {
+ my $end_marker = quotemeta(defined($1) ? $2 : $3);
+ my @tmaplines;
+ while (1) {
+ $self->{lastline} = readline($self->{FH});
+ $self->death("Error: Unterminated typemap") if not defined $self->{lastline};
+ last if $self->{lastline} =~ /^$end_marker\s*$/;
+ push @tmaplines, $self->{lastline};
+ }
+
+ my $tmapcode = join "", @tmaplines;
+ my $tmap = ExtUtils::Typemaps->new(
+ string => $tmapcode,
+ lineno_offset => ($self->current_line_number()||0)+1,
+ fake_filename => $self->{filename},
+ );
+ $self->{typemap}->merge(typemap => $tmap, replace => 1);
+
+ $self->{lastline} = "";
+ }
+
+ if ($self->{lastline} !~ /^\s*#/ ||
+ # CPP directives:
+ # ANSI: if ifdef ifndef elif else endif define undef
+ # line error pragma
+ # gcc: warning include_next
+ # obj-c: import
+ # others: ident (gcc notes that some cpps have this one)
+ $self->{lastline} =~ /^#[ \t]*(?:(?:if|ifn?def|elif|else|endif|define|undef|pragma|error|warning|line\s+\d+|ident)\b|(?:include(?:_next)?|import)\s*["<].*[>"])/) {
+ last if $self->{lastline} =~ /^\S/ && @{ $self->{line} } && $self->{line}->[-1] eq "";
+ push(@{ $self->{line} }, $self->{lastline});
+ push(@{ $self->{line_no} }, $self->{lastline_no});
+ }
+
+ # Read next line and continuation lines
+ last unless defined($self->{lastline} = readline($self->{FH}));
+ $self->{lastline_no} = $.;
+ my $tmp_line;
+ $self->{lastline} .= $tmp_line
+ while ($self->{lastline} =~ /\\$/ && defined($tmp_line = readline($self->{FH})));
+
+ chomp $self->{lastline};
+ $self->{lastline} =~ s/^\s+$//;
+ }
+ pop(@{ $self->{line} }), pop(@{ $self->{line_no} }) while @{ $self->{line} } && $self->{line}->[-1] eq "";
+ 1;
+}
+
+sub output_init {
+ my $argsref = shift;
+ my ($type, $num, $var, $init, $printed_name) = (
+ $argsref->{type},
+ $argsref->{num},
+ $argsref->{var},
+ $argsref->{init},
+ $argsref->{printed_name}
+ );
+ my $arg = "ST(" . ($num - 1) . ")";
+
+ if ( $init =~ /^=/ ) {
+ if ($printed_name) {
+ eval qq/print " $init\\n"/;
+ }
+ else {
+ eval qq/print "\\t$var $init\\n"/;
+ }
+ warn $@ if $@;
+ }
+ else {
+ if ( $init =~ s/^\+// && $num ) {
+ generate_init( {
+ type => $type,
+ num => $num,
+ var => $var,
+ printed_name => $printed_name,
+ } );
+ }
+ elsif ($printed_name) {
+ print ";\n";
+ $init =~ s/^;//;
+ }
+ else {
+ eval qq/print "\\t$var;\\n"/;
+ warn $@ if $@;
+ $init =~ s/^;//;
+ }
+ $self->{deferred} .= eval qq/"\\n\\t$init\\n"/;
+ warn $@ if $@;
+ }
+}
+
+sub generate_init {
+ my $argsref = shift;
+ my ($type, $num, $var, $printed_name) = (
+ $argsref->{type},
+ $argsref->{num},
+ $argsref->{var},
+ $argsref->{printed_name},
+ );
+ my $arg = "ST(" . ($num - 1) . ")";
+ my ($argoff, $ntype);
+ $argoff = $num - 1;
+
+ my $typemaps = $self->{typemap};
+
+ $type = tidy_type($type);
+ $self->report_typemap_failure($typemaps, $type), return
+ unless $typemaps->get_typemap(ctype => $type);
+
+ ($ntype = $type) =~ s/\s*\*/Ptr/g;
+ my $subtype;
+ ($subtype = $ntype) =~ s/(?:Array)?(?:Ptr)?$//;
+ my $typem = $typemaps->get_typemap(ctype => $type);
+ my $xstype = $typem->xstype;
+ $xstype =~ s/OBJ$/REF/ if $func_name =~ /DESTROY$/;
+ if ($xstype eq 'T_PV' and exists $self->{lengthof}->{$var}) {
+ print "\t$var" unless $printed_name;
+ print " = ($type)SvPV($arg, STRLEN_length_of_$var);\n";
+ die "default value not supported with length(NAME) supplied"
+ if defined $self->{defaults}->{$var};
+ return;
+ }
+ $type =~ tr/:/_/ unless $self->{hiertype};
+
+ my $inputmap = $typemaps->get_inputmap(xstype => $xstype);
+ $self->blurt("Error: No INPUT definition for type '$type', typekind '" . $type->xstype . "' found"), return
+ unless defined $inputmap;
+
+ my $expr = $inputmap->cleaned_code;
+ # Note: This gruesome bit either needs heavy rethinking or documentation. I vote for the former. --Steffen
+ if ($expr =~ /DO_ARRAY_ELEM/) {
+ my $subtypemap = $typemaps->get_typemap(ctype => $subtype);
+ $self->report_typemap_failure($typemaps, $subtype), return
+ if not $subtypemap;
+ my $subinputmap = $typemaps->get_inputmap(xstype => $subtypemap->xstype);
+ $self->blurt("Error: No INPUT definition for type '$subtype', typekind '" . $subtypemap->xstype . "' found"), return
+ unless $subinputmap;
+ my $subexpr = $subinputmap->cleaned_code;
+ $subexpr =~ s/\$type/\$subtype/g;
+ $subexpr =~ s/ntype/subtype/g;
+ $subexpr =~ s/\$arg/ST(ix_$var)/g;
+ $subexpr =~ s/\n\t/\n\t\t/g;
+ $subexpr =~ s/is not of (.*\")/[arg %d] is not of $1, ix_$var + 1/g;
+ $subexpr =~ s/\$var/${var}\[ix_$var - $argoff]/;
+ $expr =~ s/DO_ARRAY_ELEM/$subexpr/;
+ }
+ if ($expr =~ m#/\*.*scope.*\*/#i) { # "scope" in C comments
+ $self->{ScopeThisXSUB} = 1;
+ }
+ if (defined($self->{defaults}->{$var})) {
+ $expr =~ s/(\t+)/$1 /g;
+ $expr =~ s/ /\t/g;
+ if ($printed_name) {
+ print ";\n";
+ }
+ else {
+ eval qq/print "\\t$var;\\n"/;
+ warn $@ if $@;
+ }
+ if ($self->{defaults}->{$var} eq 'NO_INIT') {
+ $self->{deferred} .= eval qq/"\\n\\tif (items >= $num) {\\n$expr;\\n\\t}\\n"/;
+ }
+ else {
+ $self->{deferred} .= eval qq/"\\n\\tif (items < $num)\\n\\t $var = $self->{defaults}->{$var};\\n\\telse {\\n$expr;\\n\\t}\\n"/;
+ }
+ warn $@ if $@;
+ }
+ elsif ($self->{ScopeThisXSUB} or $expr !~ /^\s*\$var =/) {
+ if ($printed_name) {
+ print ";\n";
+ }
+ else {
+ eval qq/print "\\t$var;\\n"/;
+ warn $@ if $@;
+ }
+ $self->{deferred} .= eval qq/"\\n$expr;\\n"/;
+ warn $@ if $@;
+ }
+ else {
+ die "panic: do not know how to handle this branch for function pointers"
+ if $printed_name;
+ eval qq/print "$expr;\\n"/;
+ warn $@ if $@;
+ }
+}
+
+sub generate_output {
+ my $argsref = shift;
+ my ($type, $num, $var, $do_setmagic, $do_push) = (
+ $argsref->{type},
+ $argsref->{num},
+ $argsref->{var},
+ $argsref->{do_setmagic},
+ $argsref->{do_push}
+ );
+ my $arg = "ST(" . ($num - ($num != 0)) . ")";
+ my $ntype;
+
+ my $typemaps = $self->{typemap};
+
+ $type = tidy_type($type);
+ if ($type =~ /^array\(([^,]*),(.*)\)/) {
+ print "\t$arg = sv_newmortal();\n";
+ print "\tsv_setpvn($arg, (char *)$var, $2 * sizeof($1));\n";
+ print "\tSvSETMAGIC($arg);\n" if $do_setmagic;
+ }
+ else {
+ my $typemap = $typemaps->get_typemap(ctype => $type);
+ $self->report_typemap_failure($typemaps, $type), return
+ if not $typemap;
+ my $outputmap = $typemaps->get_outputmap(xstype => $typemap->xstype);
+ $self->blurt("Error: No OUTPUT definition for type '$type', typekind '" . $typemap->xstype . "' found"), return
+ unless $outputmap;
+ ($ntype = $type) =~ s/\s*\*/Ptr/g;
+ $ntype =~ s/\(\)//g;
+ my $subtype;
+ ($subtype = $ntype) =~ s/(?:Array)?(?:Ptr)?$//;
+
+ my $expr = $outputmap->cleaned_code;
+ if ($expr =~ /DO_ARRAY_ELEM/) {
+ my $subtypemap = $typemaps->get_typemap(ctype => $subtype);
+ $self->report_typemap_failure($typemaps, $subtype), return
+ if not $subtypemap;
+ my $suboutputmap = $typemaps->get_outputmap(xstype => $subtypemap->xstype);
+ $self->blurt("Error: No OUTPUT definition for type '$subtype', typekind '" . $subtypemap->xstype . "' found"), return
+ unless $suboutputmap;
+ my $subexpr = $suboutputmap->cleaned_code;
+ $subexpr =~ s/ntype/subtype/g;
+ $subexpr =~ s/\$arg/ST(ix_$var)/g;
+ $subexpr =~ s/\$var/${var}\[ix_$var]/g;
+ $subexpr =~ s/\n\t/\n\t\t/g;
+ $expr =~ s/DO_ARRAY_ELEM\n/$subexpr/;
+ eval "print qq\a$expr\a";
+ warn $@ if $@;
+ print "\t\tSvSETMAGIC(ST(ix_$var));\n" if $do_setmagic;
+ }
+ elsif ($var eq 'RETVAL') {
+ if ($expr =~ /^\t\$arg = new/) {
+ # We expect that $arg has refcnt 1, so we need to
+ # mortalize it.
+ eval "print qq\a$expr\a";
+ warn $@ if $@;
+ print "\tsv_2mortal(ST($num));\n";
+ print "\tSvSETMAGIC(ST($num));\n" if $do_setmagic;
+ }
+ elsif ($expr =~ /^\s*\$arg\s*=/) {
+ # We expect that $arg has refcnt >=1, so we need
+ # to mortalize it!
+ eval "print qq\a$expr\a";
+ warn $@ if $@;
+ print "\tsv_2mortal(ST(0));\n";
+ print "\tSvSETMAGIC(ST(0));\n" if $do_setmagic;
+ }
+ else {
+ # Just hope that the entry would safely write it
+ # over an already mortalized value. By
+ # coincidence, something like $arg = &sv_undef
+ # works too.
+ print "\tST(0) = sv_newmortal();\n";
+ eval "print qq\a$expr\a";
+ warn $@ if $@;
+ # new mortals don't have set magic
+ }
+ }
+ elsif ($do_push) {
+ print "\tPUSHs(sv_newmortal());\n";
+ $arg = "ST($num)";
+ eval "print qq\a$expr\a";
+ warn $@ if $@;
+ print "\tSvSETMAGIC($arg);\n" if $do_setmagic;
+ }
+ elsif ($arg =~ /^ST\(\d+\)$/) {
+ eval "print qq\a$expr\a";
+ warn $@ if $@;
+ print "\tSvSETMAGIC($arg);\n" if $do_setmagic;
+ }
+ }
+}
+
+1;
+
+# vim: ts=2 sw=2 et:
diff --git a/gnu/usr.bin/perl/dist/ExtUtils-ParseXS/lib/ExtUtils/ParseXS.pod b/gnu/usr.bin/perl/dist/ExtUtils-ParseXS/lib/ExtUtils/ParseXS.pod
new file mode 100644
index 00000000000..e0d1511e4a9
--- /dev/null
+++ b/gnu/usr.bin/perl/dist/ExtUtils-ParseXS/lib/ExtUtils/ParseXS.pod
@@ -0,0 +1,161 @@
+=head1 NAME
+
+ExtUtils::ParseXS - converts Perl XS code into C code
+
+=head1 SYNOPSIS
+
+ use ExtUtils::ParseXS qw(process_file);
+
+ process_file( filename => 'foo.xs' );
+
+ process_file( filename => 'foo.xs',
+ output => 'bar.c',
+ 'C++' => 1,
+ typemap => 'path/to/typemap',
+ hiertype => 1,
+ except => 1,
+ prototypes => 1,
+ versioncheck => 1,
+ linenumbers => 1,
+ optimize => 1,
+ prototypes => 1,
+ );
+
+=head1 DESCRIPTION
+
+C<ExtUtils::ParseXS> will compile XS code into C code by embedding the constructs
+necessary to let C functions manipulate Perl values and creates the glue
+necessary to let Perl access those functions. The compiler uses typemaps to
+determine how to map C function parameters and variables to Perl values.
+
+The compiler will search for typemap files called I<typemap>. It will use
+the following search path to find default typemaps, with the rightmost
+typemap taking precedence.
+
+ ../../../typemap:../../typemap:../typemap:typemap
+
+=head1 EXPORT
+
+None by default. C<process_file()> may be exported upon request.
+
+=head1 FUNCTIONS
+
+=over 4
+
+=item process_file()
+
+This function processes an XS file and sends output to a C file.
+Named parameters control how the processing is done. The following
+parameters are accepted:
+
+=over 4
+
+=item B<C++>
+
+Adds C<extern "C"> to the C code. Default is false.
+
+=item B<hiertype>
+
+Retains C<::> in type names so that C++ hierarchical types can be
+mapped. Default is false.
+
+=item B<except>
+
+Adds exception handling stubs to the C code. Default is false.
+
+=item B<typemap>
+
+Indicates that a user-supplied typemap should take precedence over the
+default typemaps. A single typemap may be specified as a string, or
+multiple typemaps can be specified in an array reference, with the
+last typemap having the highest precedence.
+
+=item B<prototypes>
+
+Generates prototype code for all xsubs. Default is false.
+
+=item B<versioncheck>
+
+Makes sure at run time that the object file (derived from the C<.xs>
+file) and the C<.pm> files have the same version number. Default is
+true.
+
+=item B<linenumbers>
+
+Adds C<#line> directives to the C output so error messages will look
+like they came from the original XS file. Default is true.
+
+=item B<optimize>
+
+Enables certain optimizations. The only optimization that is currently
+affected is the use of I<target>s by the output C code (see L<perlguts>).
+Not optimizing may significantly slow down the generated code, but this is the way
+B<xsubpp> of 5.005 and earlier operated. Default is to optimize.
+
+=item B<inout>
+
+Enable recognition of C<IN>, C<OUT_LIST> and C<INOUT_LIST>
+declarations. Default is true.
+
+=item B<argtypes>
+
+Enable recognition of ANSI-like descriptions of function signature.
+Default is true.
+
+=item B<s>
+
+I<Maintainer note:> I have no clue what this does. Strips function prefixes?
+
+=back
+
+=item errors()
+
+This function returns the number of [a certain kind of] errors
+encountered during processing of the XS file.
+
+=back
+
+=head1 AUTHOR
+
+Based on xsubpp code, written by Larry Wall.
+
+Maintained by:
+
+=over 4
+
+=item *
+
+Ken Williams, <ken@mathforum.org>
+
+=item *
+
+David Golden, <dagolden@cpan.org>
+
+=item *
+
+James Keenan, <jkeenan@cpan.org>
+
+=item *
+
+Steffen Mueller, <smueller@cpan.org>
+
+=back
+
+=head1 COPYRIGHT
+
+Copyright 2002-2012 by Ken Williams, David Golden and other contributors. All
+rights reserved.
+
+This library is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+Based on the C<ExtUtils::xsubpp> code by Larry Wall and the Perl 5
+Porters, which was released under the same license terms.
+
+=head1 SEE ALSO
+
+L<perl>, ExtUtils::xsubpp, ExtUtils::MakeMaker, L<perlxs>, L<perlxstut>.
+
+=cut
+
+
diff --git a/gnu/usr.bin/perl/dist/ExtUtils-ParseXS/lib/ExtUtils/ParseXS/Constants.pm b/gnu/usr.bin/perl/dist/ExtUtils-ParseXS/lib/ExtUtils/ParseXS/Constants.pm
new file mode 100644
index 00000000000..2f822dacbe9
--- /dev/null
+++ b/gnu/usr.bin/perl/dist/ExtUtils-ParseXS/lib/ExtUtils/ParseXS/Constants.pm
@@ -0,0 +1,42 @@
+package ExtUtils::ParseXS::Constants;
+use strict;
+use warnings;
+use Symbol;
+
+our $VERSION = '3.16';
+
+=head1 NAME
+
+ExtUtils::ParseXS::Constants - Initialization values for some globals
+
+=head1 SYNOPSIS
+
+ use ExtUtils::ParseXS::Constants ();
+
+ $PrototypeRegexp = $ExtUtils::ParseXS::Constants::PrototypeRegexp;
+
+=head1 DESCRIPTION
+
+Initialization of certain non-subroutine variables in ExtUtils::ParseXS and some of its
+supporting packages has been moved into this package so that those values can
+be defined exactly once and then re-used in any package.
+
+Nothing is exported. Use fully qualified variable names.
+
+=cut
+
+# FIXME: THESE ARE NOT CONSTANTS!
+our @InitFileCode;
+
+# Note that to reduce maintenance, $PrototypeRegexp is used
+# by ExtUtils::Typemaps, too!
+our $PrototypeRegexp = "[" . quotemeta('\$%&*@;[]_') . "]";
+our @XSKeywords = qw(
+ REQUIRE BOOT CASE PREINIT INPUT INIT CODE PPCODE
+ OUTPUT CLEANUP ALIAS ATTRS PROTOTYPES PROTOTYPE
+ VERSIONCHECK INCLUDE INCLUDE_COMMAND SCOPE INTERFACE
+ INTERFACE_MACRO C_ARGS POSTCALL OVERLOAD FALLBACK
+ EXPORT_XSUB_SYMBOLS
+);
+
+1;
diff --git a/gnu/usr.bin/perl/dist/ExtUtils-ParseXS/lib/ExtUtils/ParseXS/CountLines.pm b/gnu/usr.bin/perl/dist/ExtUtils-ParseXS/lib/ExtUtils/ParseXS/CountLines.pm
new file mode 100644
index 00000000000..66944cd629d
--- /dev/null
+++ b/gnu/usr.bin/perl/dist/ExtUtils-ParseXS/lib/ExtUtils/ParseXS/CountLines.pm
@@ -0,0 +1,54 @@
+package ExtUtils::ParseXS::CountLines;
+use strict;
+
+our $VERSION = '3.16';
+
+our $SECTION_END_MARKER;
+
+sub TIEHANDLE {
+ my ($class, $cfile, $fh) = @_;
+ $cfile =~ s/\\/\\\\/g;
+ $cfile =~ s/"/\\"/g;
+ $SECTION_END_MARKER = qq{#line --- "$cfile"};
+
+ return bless {
+ buffer => '',
+ fh => $fh,
+ line_no => 1,
+ }, $class;
+}
+
+sub PRINT {
+ my $self = shift;
+ for (@_) {
+ $self->{buffer} .= $_;
+ while ($self->{buffer} =~ s/^([^\n]*\n)//) {
+ my $line = $1;
+ ++$self->{line_no};
+ $line =~ s|^\#line\s+---(?=\s)|#line $self->{line_no}|;
+ print {$self->{fh}} $line;
+ }
+ }
+}
+
+sub PRINTF {
+ my $self = shift;
+ my $fmt = shift;
+ $self->PRINT(sprintf($fmt, @_));
+}
+
+sub DESTROY {
+ # Not necessary if we're careful to end with a "\n"
+ my $self = shift;
+ print {$self->{fh}} $self->{buffer};
+}
+
+sub UNTIE {
+ # This sub does nothing, but is necessary for references to be released.
+}
+
+sub end_marker {
+ return $SECTION_END_MARKER;
+}
+
+1;
diff --git a/gnu/usr.bin/perl/dist/ExtUtils-ParseXS/lib/ExtUtils/ParseXS/Utilities.pm b/gnu/usr.bin/perl/dist/ExtUtils-ParseXS/lib/ExtUtils/ParseXS/Utilities.pm
new file mode 100644
index 00000000000..c4172d017ee
--- /dev/null
+++ b/gnu/usr.bin/perl/dist/ExtUtils-ParseXS/lib/ExtUtils/ParseXS/Utilities.pm
@@ -0,0 +1,924 @@
+package ExtUtils::ParseXS::Utilities;
+use strict;
+use warnings;
+use Exporter;
+use File::Spec;
+use lib qw( lib );
+use ExtUtils::ParseXS::Constants ();
+
+our $VERSION = '3.16';
+
+our (@ISA, @EXPORT_OK);
+@ISA = qw(Exporter);
+@EXPORT_OK = qw(
+ standard_typemap_locations
+ trim_whitespace
+ tidy_type
+ C_string
+ valid_proto_string
+ process_typemaps
+ make_targetable
+ map_type
+ standard_XS_defs
+ assign_func_args
+ analyze_preprocessor_statements
+ set_cond
+ Warn
+ current_line_number
+ blurt
+ death
+ check_conditional_preprocessor_statements
+ escape_file_for_line_directive
+ report_typemap_failure
+);
+
+=head1 NAME
+
+ExtUtils::ParseXS::Utilities - Subroutines used with ExtUtils::ParseXS
+
+=head1 SYNOPSIS
+
+ use ExtUtils::ParseXS::Utilities qw(
+ standard_typemap_locations
+ trim_whitespace
+ tidy_type
+ C_string
+ valid_proto_string
+ process_typemaps
+ make_targetable
+ map_type
+ standard_XS_defs
+ assign_func_args
+ analyze_preprocessor_statements
+ set_cond
+ Warn
+ blurt
+ death
+ check_conditional_preprocessor_statements
+ escape_file_for_line_directive
+ report_typemap_failure
+ );
+
+=head1 SUBROUTINES
+
+The following functions are not considered to be part of the public interface.
+They are documented here for the benefit of future maintainers of this module.
+
+=head2 C<standard_typemap_locations()>
+
+=over 4
+
+=item * Purpose
+
+Provide a list of filepaths where F<typemap> files may be found. The
+filepaths -- relative paths to files (not just directory paths) -- appear in this list in lowest-to-highest priority.
+
+The highest priority is to look in the current directory.
+
+ 'typemap'
+
+The second and third highest priorities are to look in the parent of the
+current directory and a directory called F<lib/ExtUtils> underneath the parent
+directory.
+
+ '../typemap',
+ '../lib/ExtUtils/typemap',
+
+The fourth through ninth highest priorities are to look in the corresponding
+grandparent, great-grandparent and great-great-grandparent directories.
+
+ '../../typemap',
+ '../../lib/ExtUtils/typemap',
+ '../../../typemap',
+ '../../../lib/ExtUtils/typemap',
+ '../../../../typemap',
+ '../../../../lib/ExtUtils/typemap',
+
+The tenth and subsequent priorities are to look in directories named
+F<ExtUtils> which are subdirectories of directories found in C<@INC> --
+I<provided> a file named F<typemap> actually exists in such a directory.
+Example:
+
+ '/usr/local/lib/perl5/5.10.1/ExtUtils/typemap',
+
+However, these filepaths appear in the list returned by
+C<standard_typemap_locations()> in reverse order, I<i.e.>, lowest-to-highest.
+
+ '/usr/local/lib/perl5/5.10.1/ExtUtils/typemap',
+ '../../../../lib/ExtUtils/typemap',
+ '../../../../typemap',
+ '../../../lib/ExtUtils/typemap',
+ '../../../typemap',
+ '../../lib/ExtUtils/typemap',
+ '../../typemap',
+ '../lib/ExtUtils/typemap',
+ '../typemap',
+ 'typemap'
+
+=item * Arguments
+
+ my @stl = standard_typemap_locations( \@INC );
+
+Reference to C<@INC>.
+
+=item * Return Value
+
+Array holding list of directories to be searched for F<typemap> files.
+
+=back
+
+=cut
+
+sub standard_typemap_locations {
+ my $include_ref = shift;
+ my @tm = qw(typemap);
+
+ my $updir = File::Spec->updir();
+ foreach my $dir (
+ File::Spec->catdir(($updir) x 1),
+ File::Spec->catdir(($updir) x 2),
+ File::Spec->catdir(($updir) x 3),
+ File::Spec->catdir(($updir) x 4),
+ ) {
+ unshift @tm, File::Spec->catfile($dir, 'typemap');
+ unshift @tm, File::Spec->catfile($dir, lib => ExtUtils => 'typemap');
+ }
+ foreach my $dir (@{ $include_ref}) {
+ my $file = File::Spec->catfile($dir, ExtUtils => 'typemap');
+ unshift @tm, $file if -e $file;
+ }
+ return @tm;
+}
+
+=head2 C<trim_whitespace()>
+
+=over 4
+
+=item * Purpose
+
+Perform an in-place trimming of leading and trailing whitespace from the
+first argument provided to the function.
+
+=item * Argument
+
+ trim_whitespace($arg);
+
+=item * Return Value
+
+None. Remember: this is an I<in-place> modification of the argument.
+
+=back
+
+=cut
+
+sub trim_whitespace {
+ $_[0] =~ s/^\s+|\s+$//go;
+}
+
+=head2 C<tidy_type()>
+
+=over 4
+
+=item * Purpose
+
+Rationalize any asterisks (C<*>) by joining them into bunches, removing
+interior whitespace, then trimming leading and trailing whitespace.
+
+=item * Arguments
+
+ ($ret_type) = tidy_type($_);
+
+String to be cleaned up.
+
+=item * Return Value
+
+String cleaned up.
+
+=back
+
+=cut
+
+sub tidy_type {
+ local ($_) = @_;
+
+ # rationalise any '*' by joining them into bunches and removing whitespace
+ s#\s*(\*+)\s*#$1#g;
+ s#(\*+)# $1 #g;
+
+ # change multiple whitespace into a single space
+ s/\s+/ /g;
+
+ # trim leading & trailing whitespace
+ trim_whitespace($_);
+
+ $_;
+}
+
+=head2 C<C_string()>
+
+=over 4
+
+=item * Purpose
+
+Escape backslashes (C<\>) in prototype strings.
+
+=item * Arguments
+
+ $ProtoThisXSUB = C_string($_);
+
+String needing escaping.
+
+=item * Return Value
+
+Properly escaped string.
+
+=back
+
+=cut
+
+sub C_string {
+ my($string) = @_;
+
+ $string =~ s[\\][\\\\]g;
+ $string;
+}
+
+=head2 C<valid_proto_string()>
+
+=over 4
+
+=item * Purpose
+
+Validate prototype string.
+
+=item * Arguments
+
+String needing checking.
+
+=item * Return Value
+
+Upon success, returns the same string passed as argument.
+
+Upon failure, returns C<0>.
+
+=back
+
+=cut
+
+sub valid_proto_string {
+ my($string) = @_;
+
+ if ( $string =~ /^$ExtUtils::ParseXS::Constants::PrototypeRegexp+$/ ) {
+ return $string;
+ }
+
+ return 0;
+}
+
+=head2 C<process_typemaps()>
+
+=over 4
+
+=item * Purpose
+
+Process all typemap files.
+
+=item * Arguments
+
+ my $typemaps_object = process_typemaps( $args{typemap}, $pwd );
+
+List of two elements: C<typemap> element from C<%args>; current working
+directory.
+
+=item * Return Value
+
+Upon success, returns an L<ExtUtils::Typemaps> object.
+
+=back
+
+=cut
+
+sub process_typemaps {
+ my ($tmap, $pwd) = @_;
+
+ my @tm = ref $tmap ? @{$tmap} : ($tmap);
+
+ foreach my $typemap (@tm) {
+ die "Can't find $typemap in $pwd\n" unless -r $typemap;
+ }
+
+ push @tm, standard_typemap_locations( \@INC );
+
+ require ExtUtils::Typemaps;
+ my $typemap = ExtUtils::Typemaps->new;
+ foreach my $typemap_loc (@tm) {
+ next unless -f $typemap_loc;
+ # skip directories, binary files etc.
+ warn("Warning: ignoring non-text typemap file '$typemap_loc'\n"), next
+ unless -T $typemap_loc;
+
+ $typemap->merge(file => $typemap_loc, replace => 1);
+ }
+
+ return $typemap;
+}
+
+=head2 C<make_targetable()>
+
+=over 4
+
+=item * Purpose
+
+Populate C<%targetable>. This constitutes a refinement of the output of
+C<process_typemaps()> with respect to its fourth output, C<$output_expr_ref>.
+
+=item * Arguments
+
+ %targetable = make_targetable($output_expr_ref);
+
+Single hash reference: the fourth such ref returned by C<process_typemaps()>.
+
+=item * Return Value
+
+Hash.
+
+=back
+
+=cut
+
+sub make_targetable {
+ my $output_expr_ref = shift;
+
+ our $bal; # ()-balanced
+ $bal = qr[
+ (?:
+ (?>[^()]+)
+ |
+ \( (??{ $bal }) \)
+ )*
+ ]x;
+
+ # matches variations on (SV*)
+ my $sv_cast = qr[
+ (?:
+ \( \s* SV \s* \* \s* \) \s*
+ )?
+ ]x;
+
+ my $size = qr[ # Third arg (to setpvn)
+ , \s* (??{ $bal })
+ ]x;
+
+ my %targetable;
+ foreach my $key (keys %{ $output_expr_ref }) {
+ # We can still bootstrap compile 're', because in code re.pm is
+ # available to miniperl, and does not attempt to load the XS code.
+ use re 'eval';
+
+ my ($type, $with_size, $arg, $sarg) =
+ ($output_expr_ref->{$key} =~
+ m[^
+ \s+
+ sv_set([iunp])v(n)? # Type, is_setpvn
+ \s*
+ \( \s*
+ $sv_cast \$arg \s* , \s*
+ ( (??{ $bal }) ) # Set from
+ ( (??{ $size }) )? # Possible sizeof set-from
+ \) \s* ; \s* $
+ ]x
+ );
+ $targetable{$key} = [$type, $with_size, $arg, $sarg] if $type;
+ }
+ return %targetable;
+}
+
+=head2 C<map_type()>
+
+=over 4
+
+=item * Purpose
+
+Performs a mapping at several places inside C<PARAGRAPH> loop.
+
+=item * Arguments
+
+ $type = map_type($self, $type, $varname);
+
+List of three arguments.
+
+=item * Return Value
+
+String holding augmented version of second argument.
+
+=back
+
+=cut
+
+sub map_type {
+ my ($self, $type, $varname) = @_;
+
+ # C++ has :: in types too so skip this
+ $type =~ tr/:/_/ unless $self->{hiertype};
+ $type =~ s/^array\(([^,]*),(.*)\).*/$1 */s;
+ if ($varname) {
+ if ($type =~ / \( \s* \* (?= \s* \) ) /xg) {
+ (substr $type, pos $type, 0) = " $varname ";
+ }
+ else {
+ $type .= "\t$varname";
+ }
+ }
+ return $type;
+}
+
+=head2 C<standard_XS_defs()>
+
+=over 4
+
+=item * Purpose
+
+Writes to the C<.c> output file certain preprocessor directives and function
+headers needed in all such files.
+
+=item * Arguments
+
+None.
+
+=item * Return Value
+
+Returns true.
+
+=back
+
+=cut
+
+sub standard_XS_defs {
+ print <<"EOF";
+#ifndef PERL_UNUSED_VAR
+# define PERL_UNUSED_VAR(var) if (0) var = var
+#endif
+
+#ifndef dVAR
+# define dVAR dNOOP
+#endif
+
+
+/* This stuff is not part of the API! You have been warned. */
+#ifndef PERL_VERSION_DECIMAL
+# define PERL_VERSION_DECIMAL(r,v,s) (r*1000000 + v*1000 + s)
+#endif
+#ifndef PERL_DECIMAL_VERSION
+# define PERL_DECIMAL_VERSION \\
+ PERL_VERSION_DECIMAL(PERL_REVISION,PERL_VERSION,PERL_SUBVERSION)
+#endif
+#ifndef PERL_VERSION_GE
+# define PERL_VERSION_GE(r,v,s) \\
+ (PERL_DECIMAL_VERSION >= PERL_VERSION_DECIMAL(r,v,s))
+#endif
+#ifndef PERL_VERSION_LE
+# define PERL_VERSION_LE(r,v,s) \\
+ (PERL_DECIMAL_VERSION <= PERL_VERSION_DECIMAL(r,v,s))
+#endif
+
+/* XS_INTERNAL is the explicit static-linkage variant of the default
+ * XS macro.
+ *
+ * XS_EXTERNAL is the same as XS_INTERNAL except it does not include
+ * "STATIC", ie. it exports XSUB symbols. You probably don't want that
+ * for anything but the BOOT XSUB.
+ *
+ * See XSUB.h in core!
+ */
+
+
+/* TODO: This might be compatible further back than 5.10.0. */
+#if PERL_VERSION_GE(5, 10, 0) && PERL_VERSION_LE(5, 15, 1)
+# undef XS_EXTERNAL
+# undef XS_INTERNAL
+# if defined(__CYGWIN__) && defined(USE_DYNAMIC_LOADING)
+# define XS_EXTERNAL(name) __declspec(dllexport) XSPROTO(name)
+# define XS_INTERNAL(name) STATIC XSPROTO(name)
+# endif
+# if defined(__SYMBIAN32__)
+# define XS_EXTERNAL(name) EXPORT_C XSPROTO(name)
+# define XS_INTERNAL(name) EXPORT_C STATIC XSPROTO(name)
+# endif
+# ifndef XS_EXTERNAL
+# if defined(HASATTRIBUTE_UNUSED) && !defined(__cplusplus)
+# define XS_EXTERNAL(name) void name(pTHX_ CV* cv __attribute__unused__)
+# define XS_INTERNAL(name) STATIC void name(pTHX_ CV* cv __attribute__unused__)
+# else
+# ifdef __cplusplus
+# define XS_EXTERNAL(name) extern "C" XSPROTO(name)
+# define XS_INTERNAL(name) static XSPROTO(name)
+# else
+# define XS_EXTERNAL(name) XSPROTO(name)
+# define XS_INTERNAL(name) STATIC XSPROTO(name)
+# endif
+# endif
+# endif
+#endif
+
+/* perl >= 5.10.0 && perl <= 5.15.1 */
+
+
+/* The XS_EXTERNAL macro is used for functions that must not be static
+ * like the boot XSUB of a module. If perl didn't have an XS_EXTERNAL
+ * macro defined, the best we can do is assume XS is the same.
+ * Dito for XS_INTERNAL.
+ */
+#ifndef XS_EXTERNAL
+# define XS_EXTERNAL(name) XS(name)
+#endif
+#ifndef XS_INTERNAL
+# define XS_INTERNAL(name) XS(name)
+#endif
+
+/* Now, finally, after all this mess, we want an ExtUtils::ParseXS
+ * internal macro that we're free to redefine for varying linkage due
+ * to the EXPORT_XSUB_SYMBOLS XS keyword. This is internal, use
+ * XS_EXTERNAL(name) or XS_INTERNAL(name) in your code if you need to!
+ */
+
+#undef XS_EUPXS
+#if defined(PERL_EUPXS_ALWAYS_EXPORT)
+# define XS_EUPXS(name) XS_EXTERNAL(name)
+#else
+ /* default to internal */
+# define XS_EUPXS(name) XS_INTERNAL(name)
+#endif
+
+EOF
+
+ print <<"EOF";
+#ifndef PERL_ARGS_ASSERT_CROAK_XS_USAGE
+#define PERL_ARGS_ASSERT_CROAK_XS_USAGE assert(cv); assert(params)
+
+/* prototype to pass -Wmissing-prototypes */
+STATIC void
+S_croak_xs_usage(pTHX_ const CV *const cv, const char *const params);
+
+STATIC void
+S_croak_xs_usage(pTHX_ const CV *const cv, const char *const params)
+{
+ const GV *const gv = CvGV(cv);
+
+ PERL_ARGS_ASSERT_CROAK_XS_USAGE;
+
+ if (gv) {
+ const char *const gvname = GvNAME(gv);
+ const HV *const stash = GvSTASH(gv);
+ const char *const hvname = stash ? HvNAME(stash) : NULL;
+
+ if (hvname)
+ Perl_croak(aTHX_ "Usage: %s::%s(%s)", hvname, gvname, params);
+ else
+ Perl_croak(aTHX_ "Usage: %s(%s)", gvname, params);
+ } else {
+ /* Pants. I don't think that it should be possible to get here. */
+ Perl_croak(aTHX_ "Usage: CODE(0x%"UVxf")(%s)", PTR2UV(cv), params);
+ }
+}
+#undef PERL_ARGS_ASSERT_CROAK_XS_USAGE
+
+#ifdef PERL_IMPLICIT_CONTEXT
+#define croak_xs_usage(a,b) S_croak_xs_usage(aTHX_ a,b)
+#else
+#define croak_xs_usage S_croak_xs_usage
+#endif
+
+#endif
+
+/* NOTE: the prototype of newXSproto() is different in versions of perls,
+ * so we define a portable version of newXSproto()
+ */
+#ifdef newXS_flags
+#define newXSproto_portable(name, c_impl, file, proto) newXS_flags(name, c_impl, file, proto, 0)
+#else
+#define newXSproto_portable(name, c_impl, file, proto) (PL_Sv=(SV*)newXS(name, c_impl, file), sv_setpv(PL_Sv, proto), (CV*)PL_Sv)
+#endif /* !defined(newXS_flags) */
+
+EOF
+ return 1;
+}
+
+=head2 C<assign_func_args()>
+
+=over 4
+
+=item * Purpose
+
+Perform assignment to the C<func_args> attribute.
+
+=item * Arguments
+
+ $string = assign_func_args($self, $argsref, $class);
+
+List of three elements. Second is an array reference; third is a string.
+
+=item * Return Value
+
+String.
+
+=back
+
+=cut
+
+sub assign_func_args {
+ my ($self, $argsref, $class) = @_;
+ my @func_args = @{$argsref};
+ shift @func_args if defined($class);
+
+ for my $arg (@func_args) {
+ $arg =~ s/^/&/ if $self->{in_out}->{$arg};
+ }
+ return join(", ", @func_args);
+}
+
+=head2 C<analyze_preprocessor_statements()>
+
+=over 4
+
+=item * Purpose
+
+Within each function inside each Xsub, print to the F<.c> output file certain
+preprocessor statements.
+
+=item * Arguments
+
+ ( $self, $XSS_work_idx, $BootCode_ref ) =
+ analyze_preprocessor_statements(
+ $self, $statement, $XSS_work_idx, $BootCode_ref
+ );
+
+List of four elements.
+
+=item * Return Value
+
+Modifed values of three of the arguments passed to the function. In
+particular, the C<XSStack> and C<InitFileCode> attributes are modified.
+
+=back
+
+=cut
+
+sub analyze_preprocessor_statements {
+ my ($self, $statement, $XSS_work_idx, $BootCode_ref) = @_;
+
+ if ($statement eq 'if') {
+ $XSS_work_idx = @{ $self->{XSStack} };
+ push(@{ $self->{XSStack} }, {type => 'if'});
+ }
+ else {
+ $self->death("Error: '$statement' with no matching 'if'")
+ if $self->{XSStack}->[-1]{type} ne 'if';
+ if ($self->{XSStack}->[-1]{varname}) {
+ push(@{ $self->{InitFileCode} }, "#endif\n");
+ push(@{ $BootCode_ref }, "#endif");
+ }
+
+ my(@fns) = keys %{$self->{XSStack}->[-1]{functions}};
+ if ($statement ne 'endif') {
+ # Hide the functions defined in other #if branches, and reset.
+ @{$self->{XSStack}->[-1]{other_functions}}{@fns} = (1) x @fns;
+ @{$self->{XSStack}->[-1]}{qw(varname functions)} = ('', {});
+ }
+ else {
+ my($tmp) = pop(@{ $self->{XSStack} });
+ 0 while (--$XSS_work_idx
+ && $self->{XSStack}->[$XSS_work_idx]{type} ne 'if');
+ # Keep all new defined functions
+ push(@fns, keys %{$tmp->{other_functions}});
+ @{$self->{XSStack}->[$XSS_work_idx]{functions}}{@fns} = (1) x @fns;
+ }
+ }
+ return ($self, $XSS_work_idx, $BootCode_ref);
+}
+
+=head2 C<set_cond()>
+
+=over 4
+
+=item * Purpose
+
+=item * Arguments
+
+=item * Return Value
+
+=back
+
+=cut
+
+sub set_cond {
+ my ($ellipsis, $min_args, $num_args) = @_;
+ my $cond;
+ if ($ellipsis) {
+ $cond = ($min_args ? qq(items < $min_args) : 0);
+ }
+ elsif ($min_args == $num_args) {
+ $cond = qq(items != $min_args);
+ }
+ else {
+ $cond = qq(items < $min_args || items > $num_args);
+ }
+ return $cond;
+}
+
+=head2 C<current_line_number()>
+
+=over 4
+
+=item * Purpose
+
+Figures out the current line number in the XS file.
+
+=item * Arguments
+
+C<$self>
+
+=item * Return Value
+
+The current line number.
+
+=back
+
+=cut
+
+sub current_line_number {
+ my $self = shift;
+ my $line_number = $self->{line_no}->[@{ $self->{line_no} } - @{ $self->{line} } -1];
+ return $line_number;
+}
+
+=head2 C<Warn()>
+
+=over 4
+
+=item * Purpose
+
+=item * Arguments
+
+=item * Return Value
+
+=back
+
+=cut
+
+sub Warn {
+ my $self = shift;
+ my $warn_line_number = $self->current_line_number();
+ print STDERR "@_ in $self->{filename}, line $warn_line_number\n";
+}
+
+=head2 C<blurt()>
+
+=over 4
+
+=item * Purpose
+
+=item * Arguments
+
+=item * Return Value
+
+=back
+
+=cut
+
+sub blurt {
+ my $self = shift;
+ $self->Warn(@_);
+ $self->{errors}++
+}
+
+=head2 C<death()>
+
+=over 4
+
+=item * Purpose
+
+=item * Arguments
+
+=item * Return Value
+
+=back
+
+=cut
+
+sub death {
+ my $self = shift;
+ $self->Warn(@_);
+ exit 1;
+}
+
+=head2 C<check_conditional_preprocessor_statements()>
+
+=over 4
+
+=item * Purpose
+
+=item * Arguments
+
+=item * Return Value
+
+=back
+
+=cut
+
+sub check_conditional_preprocessor_statements {
+ my ($self) = @_;
+ my @cpp = grep(/^\#\s*(?:if|e\w+)/, @{ $self->{line} });
+ if (@cpp) {
+ my $cpplevel;
+ for my $cpp (@cpp) {
+ if ($cpp =~ /^\#\s*if/) {
+ $cpplevel++;
+ }
+ elsif (!$cpplevel) {
+ $self->Warn("Warning: #else/elif/endif without #if in this function");
+ print STDERR " (precede it with a blank line if the matching #if is outside the function)\n"
+ if $self->{XSStack}->[-1]{type} eq 'if';
+ return;
+ }
+ elsif ($cpp =~ /^\#\s*endif/) {
+ $cpplevel--;
+ }
+ }
+ $self->Warn("Warning: #if without #endif in this function") if $cpplevel;
+ }
+}
+
+=head2 C<escape_file_for_line_directive()>
+
+=over 4
+
+=item * Purpose
+
+Escapes a given code source name (typically a file name but can also
+be a command that was read from) so that double-quotes and backslashes are escaped.
+
+=item * Arguments
+
+A string.
+
+=item * Return Value
+
+A string with escapes for double-quotes and backslashes.
+
+=back
+
+=cut
+
+sub escape_file_for_line_directive {
+ my $string = shift;
+ $string =~ s/\\/\\\\/g;
+ $string =~ s/"/\\"/g;
+ return $string;
+}
+
+=head2 C<report_typemap_failure>
+
+=over 4
+
+=item * Purpose
+
+Do error reporting for missing typemaps.
+
+=item * Arguments
+
+The C<ExtUtils::ParseXS> object.
+
+An C<ExtUtils::Typemaps> object.
+
+The string that represents the C type that was not found in the typemap.
+
+Optionally, the string C<death> or C<blurt> to choose
+whether the error is immediately fatal or not. Default: C<blurt>
+
+=item * Return Value
+
+Returns nothing. Depending on the arguments, this
+may call C<death> or C<blurt>, the former of which is
+fatal.
+
+=back
+
+=cut
+
+sub report_typemap_failure {
+ my ($self, $tm, $ctype, $error_method) = @_;
+ $error_method ||= 'blurt';
+
+ my @avail_ctypes = $tm->list_mapped_ctypes;
+
+ my $err = "Could not find a typemap for C type '$ctype'.\n"
+ . "The following C types are mapped by the current typemap:\n'"
+ . join("', '", @avail_ctypes) . "'\n";
+
+ $self->$error_method($err);
+ return();
+}
+
+1;
+
+# vim: ts=2 sw=2 et:
diff --git a/gnu/usr.bin/perl/dist/ExtUtils-ParseXS/lib/ExtUtils/Typemaps.pm b/gnu/usr.bin/perl/dist/ExtUtils-ParseXS/lib/ExtUtils/Typemaps.pm
new file mode 100644
index 00000000000..2bc9c8036f1
--- /dev/null
+++ b/gnu/usr.bin/perl/dist/ExtUtils-ParseXS/lib/ExtUtils/Typemaps.pm
@@ -0,0 +1,1031 @@
+package ExtUtils::Typemaps;
+use 5.006001;
+use strict;
+use warnings;
+our $VERSION = '3.16';
+#use Carp qw(croak);
+
+require ExtUtils::ParseXS;
+require ExtUtils::ParseXS::Constants;
+require ExtUtils::Typemaps::InputMap;
+require ExtUtils::Typemaps::OutputMap;
+require ExtUtils::Typemaps::Type;
+
+=head1 NAME
+
+ExtUtils::Typemaps - Read/Write/Modify Perl/XS typemap files
+
+=head1 SYNOPSIS
+
+ # read/create file
+ my $typemap = ExtUtils::Typemaps->new(file => 'typemap');
+ # alternatively create an in-memory typemap
+ # $typemap = ExtUtils::Typemaps->new();
+ # alternatively create an in-memory typemap by parsing a string
+ # $typemap = ExtUtils::Typemaps->new(string => $sometypemap);
+
+ # add a mapping
+ $typemap->add_typemap(ctype => 'NV', xstype => 'T_NV');
+ $typemap->add_inputmap(
+ xstype => 'T_NV', code => '$var = ($type)SvNV($arg);'
+ );
+ $typemap->add_outputmap(
+ xstype => 'T_NV', code => 'sv_setnv($arg, (NV)$var);'
+ );
+ $typemap->add_string(string => $typemapstring);
+ # will be parsed and merged
+
+ # remove a mapping (same for remove_typemap and remove_outputmap...)
+ $typemap->remove_inputmap(xstype => 'SomeType');
+
+ # save a typemap to a file
+ $typemap->write(file => 'anotherfile.map');
+
+ # merge the other typemap into this one
+ $typemap->merge(typemap => $another_typemap);
+
+=head1 DESCRIPTION
+
+This module can read, modify, create and write Perl XS typemap files. If you don't know
+what a typemap is, please confer the L<perlxstut> and L<perlxs> manuals.
+
+The module is not entirely round-trip safe: For example it currently simply strips all comments.
+The order of entries in the maps is, however, preserved.
+
+We check for duplicate entries in the typemap, but do not check for missing
+C<TYPEMAP> entries for C<INPUTMAP> or C<OUTPUTMAP> entries since these might be hidden
+in a different typemap.
+
+=head1 METHODS
+
+=cut
+
+=head2 new
+
+Returns a new typemap object. Takes an optional C<file> parameter.
+If set, the given file will be read. If the file doesn't exist, an empty typemap
+is returned.
+
+Alternatively, if the C<string> parameter is given, the supplied
+string will be parsed instead of a file.
+
+=cut
+
+sub new {
+ my $class = shift;
+ my %args = @_;
+
+ if (defined $args{file} and defined $args{string}) {
+ die("Cannot handle both 'file' and 'string' arguments to constructor");
+ }
+
+ my $self = bless {
+ file => undef,
+ %args,
+ typemap_section => [],
+ typemap_lookup => {},
+ input_section => [],
+ input_lookup => {},
+ output_section => [],
+ output_lookup => {},
+ } => $class;
+
+ $self->_init();
+
+ return $self;
+}
+
+sub _init {
+ my $self = shift;
+ if (defined $self->{string}) {
+ $self->_parse(\($self->{string}), $self->{lineno_offset}, $self->{fake_filename});
+ delete $self->{string};
+ }
+ elsif (defined $self->{file} and -e $self->{file}) {
+ open my $fh, '<', $self->{file}
+ or die "Cannot open typemap file '"
+ . $self->{file} . "' for reading: $!";
+ local $/ = undef;
+ my $string = <$fh>;
+ $self->_parse(\$string, $self->{lineno_offset}, $self->{file});
+ }
+}
+
+=head2 file
+
+Get/set the file that the typemap is written to when the
+C<write> method is called.
+
+=cut
+
+sub file {
+ $_[0]->{file} = $_[1] if @_ > 1;
+ $_[0]->{file}
+}
+
+=head2 add_typemap
+
+Add a C<TYPEMAP> entry to the typemap.
+
+Required named arguments: The C<ctype> (e.g. C<ctype =E<gt> 'double'>)
+and the C<xstype> (e.g. C<xstype =E<gt> 'T_NV'>).
+
+Optional named arguments: C<replace =E<gt> 1> forces removal/replacement of
+existing C<TYPEMAP> entries of the same C<ctype>. C<skip =E<gt> 1>
+triggers a I<"first come first serve"> logic by which new entries that conflict
+with existing entries are silently ignored.
+
+As an alternative to the named parameters usage, you may pass in
+an C<ExtUtils::Typemaps::Type> object as first argument, a copy of which will be
+added to the typemap. In that case, only the C<replace> or C<skip> named parameters
+may be used after the object. Example:
+
+ $map->add_typemap($type_obj, replace => 1);
+
+=cut
+
+sub add_typemap {
+ my $self = shift;
+ my $type;
+ my %args;
+
+ if ((@_ % 2) == 1) {
+ my $orig = shift;
+ $type = $orig->new();
+ %args = @_;
+ }
+ else {
+ %args = @_;
+ my $ctype = $args{ctype};
+ die("Need ctype argument") if not defined $ctype;
+ my $xstype = $args{xstype};
+ die("Need xstype argument") if not defined $xstype;
+
+ $type = ExtUtils::Typemaps::Type->new(
+ xstype => $xstype,
+ 'prototype' => $args{'prototype'},
+ ctype => $ctype,
+ );
+ }
+
+ if ($args{skip} and $args{replace}) {
+ die("Cannot use both 'skip' and 'replace'");
+ }
+
+ if ($args{replace}) {
+ $self->remove_typemap(ctype => $type->ctype);
+ }
+ elsif ($args{skip}) {
+ return() if exists $self->{typemap_lookup}{$type->ctype};
+ }
+ else {
+ $self->validate(typemap_xstype => $type->xstype, ctype => $type->ctype);
+ }
+
+ # store
+ push @{$self->{typemap_section}}, $type;
+ # remember type for lookup, too.
+ $self->{typemap_lookup}{$type->tidy_ctype} = $#{$self->{typemap_section}};
+
+ return 1;
+}
+
+=head2 add_inputmap
+
+Add an C<INPUT> entry to the typemap.
+
+Required named arguments:
+The C<xstype> (e.g. C<xstype =E<gt> 'T_NV'>)
+and the C<code> to associate with it for input.
+
+Optional named arguments: C<replace =E<gt> 1> forces removal/replacement of
+existing C<INPUT> entries of the same C<xstype>. C<skip =E<gt> 1>
+triggers a I<"first come first serve"> logic by which new entries that conflict
+with existing entries are silently ignored.
+
+As an alternative to the named parameters usage, you may pass in
+an C<ExtUtils::Typemaps::InputMap> object as first argument, a copy of which will be
+added to the typemap. In that case, only the C<replace> or C<skip> named parameters
+may be used after the object. Example:
+
+ $map->add_inputmap($type_obj, replace => 1);
+
+=cut
+
+sub add_inputmap {
+ my $self = shift;
+ my $input;
+ my %args;
+
+ if ((@_ % 2) == 1) {
+ my $orig = shift;
+ $input = $orig->new();
+ %args = @_;
+ }
+ else {
+ %args = @_;
+ my $xstype = $args{xstype};
+ die("Need xstype argument") if not defined $xstype;
+ my $code = $args{code};
+ die("Need code argument") if not defined $code;
+
+ $input = ExtUtils::Typemaps::InputMap->new(
+ xstype => $xstype,
+ code => $code,
+ );
+ }
+
+ if ($args{skip} and $args{replace}) {
+ die("Cannot use both 'skip' and 'replace'");
+ }
+
+ if ($args{replace}) {
+ $self->remove_inputmap(xstype => $input->xstype);
+ }
+ elsif ($args{skip}) {
+ return() if exists $self->{input_lookup}{$input->xstype};
+ }
+ else {
+ $self->validate(inputmap_xstype => $input->xstype);
+ }
+
+ # store
+ push @{$self->{input_section}}, $input;
+ # remember type for lookup, too.
+ $self->{input_lookup}{$input->xstype} = $#{$self->{input_section}};
+
+ return 1;
+}
+
+=head2 add_outputmap
+
+Add an C<OUTPUT> entry to the typemap.
+Works exactly the same as C<add_inputmap>.
+
+=cut
+
+sub add_outputmap {
+ my $self = shift;
+ my $output;
+ my %args;
+
+ if ((@_ % 2) == 1) {
+ my $orig = shift;
+ $output = $orig->new();
+ %args = @_;
+ }
+ else {
+ %args = @_;
+ my $xstype = $args{xstype};
+ die("Need xstype argument") if not defined $xstype;
+ my $code = $args{code};
+ die("Need code argument") if not defined $code;
+
+ $output = ExtUtils::Typemaps::OutputMap->new(
+ xstype => $xstype,
+ code => $code,
+ );
+ }
+
+ if ($args{skip} and $args{replace}) {
+ die("Cannot use both 'skip' and 'replace'");
+ }
+
+ if ($args{replace}) {
+ $self->remove_outputmap(xstype => $output->xstype);
+ }
+ elsif ($args{skip}) {
+ return() if exists $self->{output_lookup}{$output->xstype};
+ }
+ else {
+ $self->validate(outputmap_xstype => $output->xstype);
+ }
+
+ # store
+ push @{$self->{output_section}}, $output;
+ # remember type for lookup, too.
+ $self->{output_lookup}{$output->xstype} = $#{$self->{output_section}};
+
+ return 1;
+}
+
+=head2 add_string
+
+Parses a string as a typemap and merge it into the typemap object.
+
+Required named argument: C<string> to specify the string to parse.
+
+=cut
+
+sub add_string {
+ my $self = shift;
+ my %args = @_;
+ die("Need 'string' argument") if not defined $args{string};
+
+ # no, this is not elegant.
+ my $other = ExtUtils::Typemaps->new(string => $args{string});
+ $self->merge(typemap => $other);
+}
+
+=head2 remove_typemap
+
+Removes a C<TYPEMAP> entry from the typemap.
+
+Required named argument: C<ctype> to specify the entry to remove from the typemap.
+
+Alternatively, you may pass a single C<ExtUtils::Typemaps::Type> object.
+
+=cut
+
+sub remove_typemap {
+ my $self = shift;
+ my $ctype;
+ if (@_ > 1) {
+ my %args = @_;
+ $ctype = $args{ctype};
+ die("Need ctype argument") if not defined $ctype;
+ $ctype = _tidy_type($ctype);
+ }
+ else {
+ $ctype = $_[0]->tidy_ctype;
+ }
+
+ return $self->_remove($ctype, $self->{typemap_section}, $self->{typemap_lookup});
+}
+
+=head2 remove_inputmap
+
+Removes an C<INPUT> entry from the typemap.
+
+Required named argument: C<xstype> to specify the entry to remove from the typemap.
+
+Alternatively, you may pass a single C<ExtUtils::Typemaps::InputMap> object.
+
+=cut
+
+sub remove_inputmap {
+ my $self = shift;
+ my $xstype;
+ if (@_ > 1) {
+ my %args = @_;
+ $xstype = $args{xstype};
+ die("Need xstype argument") if not defined $xstype;
+ }
+ else {
+ $xstype = $_[0]->xstype;
+ }
+
+ return $self->_remove($xstype, $self->{input_section}, $self->{input_lookup});
+}
+
+=head2 remove_inputmap
+
+Removes an C<OUTPUT> entry from the typemap.
+
+Required named argument: C<xstype> to specify the entry to remove from the typemap.
+
+Alternatively, you may pass a single C<ExtUtils::Typemaps::OutputMap> object.
+
+=cut
+
+sub remove_outputmap {
+ my $self = shift;
+ my $xstype;
+ if (@_ > 1) {
+ my %args = @_;
+ $xstype = $args{xstype};
+ die("Need xstype argument") if not defined $xstype;
+ }
+ else {
+ $xstype = $_[0]->xstype;
+ }
+
+ return $self->_remove($xstype, $self->{output_section}, $self->{output_lookup});
+}
+
+sub _remove {
+ my $self = shift;
+ my $rm = shift;
+ my $array = shift;
+ my $lookup = shift;
+
+ # Just fetch the index of the item from the lookup table
+ my $index = $lookup->{$rm};
+ return() if not defined $index;
+
+ # Nuke the item from storage
+ splice(@$array, $index, 1);
+
+ # Decrement the storage position of all items thereafter
+ foreach my $key (keys %$lookup) {
+ if ($lookup->{$key} > $index) {
+ $lookup->{$key}--;
+ }
+ }
+ return();
+}
+
+=head2 get_typemap
+
+Fetches an entry of the TYPEMAP section of the typemap.
+
+Mandatory named arguments: The C<ctype> of the entry.
+
+Returns the C<ExtUtils::Typemaps::Type>
+object for the entry if found.
+
+=cut
+
+sub get_typemap {
+ my $self = shift;
+ die("Need named parameters, got uneven number") if @_ % 2;
+
+ my %args = @_;
+ my $ctype = $args{ctype};
+ die("Need ctype argument") if not defined $ctype;
+ $ctype = _tidy_type($ctype);
+
+ my $index = $self->{typemap_lookup}{$ctype};
+ return() if not defined $index;
+ return $self->{typemap_section}[$index];
+}
+
+=head2 get_inputmap
+
+Fetches an entry of the INPUT section of the
+typemap.
+
+Mandatory named arguments: The C<xstype> of the
+entry or the C<ctype> of the typemap that can be used to find
+the C<xstype>. To wit, the following pieces of code
+are equivalent:
+
+ my $type = $typemap->get_typemap(ctype => $ctype)
+ my $input_map = $typemap->get_inputmap(xstype => $type->xstype);
+
+ my $input_map = $typemap->get_inputmap(ctype => $ctype);
+
+Returns the C<ExtUtils::Typemaps::InputMap>
+object for the entry if found.
+
+=cut
+
+sub get_inputmap {
+ my $self = shift;
+ die("Need named parameters, got uneven number") if @_ % 2;
+
+ my %args = @_;
+ my $xstype = $args{xstype};
+ my $ctype = $args{ctype};
+ die("Need xstype or ctype argument")
+ if not defined $xstype
+ and not defined $ctype;
+ die("Need xstype OR ctype arguments, not both")
+ if defined $xstype and defined $ctype;
+
+ if (defined $ctype) {
+ my $tm = $self->get_typemap(ctype => $ctype);
+ $xstype = $tm && $tm->xstype;
+ return() if not defined $xstype;
+ }
+
+ my $index = $self->{input_lookup}{$xstype};
+ return() if not defined $index;
+ return $self->{input_section}[$index];
+}
+
+=head2 get_outputmap
+
+Fetches an entry of the OUTPUT section of the
+typemap.
+
+Mandatory named arguments: The C<xstype> of the
+entry or the C<ctype> of the typemap that can be used to
+resolve the C<xstype>. (See above for an example.)
+
+Returns the C<ExtUtils::Typemaps::InputMap>
+object for the entry if found.
+
+=cut
+
+sub get_outputmap {
+ my $self = shift;
+ die("Need named parameters, got uneven number") if @_ % 2;
+
+ my %args = @_;
+ my $xstype = $args{xstype};
+ my $ctype = $args{ctype};
+ die("Need xstype or ctype argument")
+ if not defined $xstype
+ and not defined $ctype;
+ die("Need xstype OR ctype arguments, not both")
+ if defined $xstype and defined $ctype;
+
+ if (defined $ctype) {
+ my $tm = $self->get_typemap(ctype => $ctype);
+ $xstype = $tm && $tm->xstype;
+ return() if not defined $xstype;
+ }
+
+ my $index = $self->{output_lookup}{$xstype};
+ return() if not defined $index;
+ return $self->{output_section}[$index];
+}
+
+=head2 write
+
+Write the typemap to a file. Optionally takes a C<file> argument. If given, the
+typemap will be written to the specified file. If not, the typemap is written
+to the currently stored file name (see C<-E<gt>file> above, this defaults to the file
+it was read from if any).
+
+=cut
+
+sub write {
+ my $self = shift;
+ my %args = @_;
+ my $file = defined $args{file} ? $args{file} : $self->file();
+ die("write() needs a file argument (or set the file name of the typemap using the 'file' method)")
+ if not defined $file;
+
+ open my $fh, '>', $file
+ or die "Cannot open typemap file '$file' for writing: $!";
+ print $fh $self->as_string();
+ close $fh;
+}
+
+=head2 as_string
+
+Generates and returns the string form of the typemap.
+
+=cut
+
+sub as_string {
+ my $self = shift;
+ my $typemap = $self->{typemap_section};
+ my @code;
+ push @code, "TYPEMAP\n";
+ foreach my $entry (@$typemap) {
+ # type kind proto
+ # /^(.*?\S)\s+(\S+)\s*($ExtUtils::ParseXS::Constants::PrototypeRegexp*)$/o
+ push @code, $entry->ctype . "\t" . $entry->xstype
+ . ($entry->proto ne '' ? "\t".$entry->proto : '') . "\n";
+ }
+
+ my $input = $self->{input_section};
+ if (@$input) {
+ push @code, "\nINPUT\n";
+ foreach my $entry (@$input) {
+ push @code, $entry->xstype, "\n", $entry->code, "\n";
+ }
+ }
+
+ my $output = $self->{output_section};
+ if (@$output) {
+ push @code, "\nOUTPUT\n";
+ foreach my $entry (@$output) {
+ push @code, $entry->xstype, "\n", $entry->code, "\n";
+ }
+ }
+ return join '', @code;
+}
+
+=head2 as_embedded_typemap
+
+Generates and returns the string form of the typemap with the
+appropriate prefix around it for verbatim inclusion into an
+XS file as an embedded typemap. This will return a string like
+
+ TYPEMAP: <<END_OF_TYPEMAP
+ ... typemap here (see as_string) ...
+ END_OF_TYPEMAP
+
+The method takes care not to use a HERE-doc end marker that
+appears in the typemap string itself.
+
+=cut
+
+sub as_embedded_typemap {
+ my $self = shift;
+ my $string = $self->as_string;
+
+ my @ident_cand = qw(END_TYPEMAP END_OF_TYPEMAP END);
+ my $icand = 0;
+ my $cand_suffix = "";
+ while ($string =~ /^\Q$ident_cand[$icand]$cand_suffix\E\s*$/m) {
+ $icand++;
+ if ($icand == @ident_cand) {
+ $icand = 0;
+ ++$cand_suffix;
+ }
+ }
+
+ my $marker = "$ident_cand[$icand]$cand_suffix";
+ return "TYPEMAP: <<$marker;\n$string\n$marker\n";
+}
+
+=head2 merge
+
+Merges a given typemap into the object. Note that a failed merge
+operation leaves the object in an inconsistent state so clone it if necessary.
+
+Mandatory named arguments: Either C<typemap =E<gt> $another_typemap_obj>
+or C<file =E<gt> $path_to_typemap_file> but not both.
+
+Optional arguments: C<replace =E<gt> 1> to force replacement
+of existing typemap entries without warning or C<skip =E<gt> 1>
+to skip entries that exist already in the typemap.
+
+=cut
+
+sub merge {
+ my $self = shift;
+ my %args = @_;
+
+ if (exists $args{typemap} and exists $args{file}) {
+ die("Need {file} OR {typemap} argument. Not both!");
+ }
+ elsif (not exists $args{typemap} and not exists $args{file}) {
+ die("Need {file} or {typemap} argument!");
+ }
+
+ my @params;
+ push @params, 'replace' => $args{replace} if exists $args{replace};
+ push @params, 'skip' => $args{skip} if exists $args{skip};
+
+ my $typemap = $args{typemap};
+ if (not defined $typemap) {
+ $typemap = ref($self)->new(file => $args{file}, @params);
+ }
+
+ # FIXME breaking encapsulation. Add accessor code.
+ foreach my $entry (@{$typemap->{typemap_section}}) {
+ $self->add_typemap( $entry, @params );
+ }
+
+ foreach my $entry (@{$typemap->{input_section}}) {
+ $self->add_inputmap( $entry, @params );
+ }
+
+ foreach my $entry (@{$typemap->{output_section}}) {
+ $self->add_outputmap( $entry, @params );
+ }
+
+ return 1;
+}
+
+=head2 is_empty
+
+Returns a bool indicating whether this typemap is entirely empty.
+
+=cut
+
+sub is_empty {
+ my $self = shift;
+
+ return @{ $self->{typemap_section} } == 0
+ && @{ $self->{input_section} } == 0
+ && @{ $self->{output_section} } == 0;
+}
+
+=head2 list_mapped_ctypes
+
+Returns a list of the C types that are mappable by
+this typemap object.
+
+=cut
+
+sub list_mapped_ctypes {
+ my $self = shift;
+ return sort keys %{ $self->{typemap_lookup} };
+}
+
+=head2 _get_typemap_hash
+
+Returns a hash mapping the C types to the XS types:
+
+ {
+ 'char **' => 'T_PACKEDARRAY',
+ 'bool_t' => 'T_IV',
+ 'AV *' => 'T_AVREF',
+ 'InputStream' => 'T_IN',
+ 'double' => 'T_DOUBLE',
+ # ...
+ }
+
+This is documented because it is used by C<ExtUtils::ParseXS>,
+but it's not intended for general consumption. May be removed
+at any time.
+
+=cut
+
+sub _get_typemap_hash {
+ my $self = shift;
+ my $lookup = $self->{typemap_lookup};
+ my $storage = $self->{typemap_section};
+
+ my %rv;
+ foreach my $ctype (keys %$lookup) {
+ $rv{$ctype} = $storage->[ $lookup->{$ctype} ]->xstype;
+ }
+
+ return \%rv;
+}
+
+=head2 _get_inputmap_hash
+
+Returns a hash mapping the XS types (identifiers) to the
+corresponding INPUT code:
+
+ {
+ 'T_CALLBACK' => ' $var = make_perl_cb_$type($arg)
+ ',
+ 'T_OUT' => ' $var = IoOFP(sv_2io($arg))
+ ',
+ 'T_REF_IV_PTR' => ' if (sv_isa($arg, \\"${ntype}\\")) {
+ # ...
+ }
+
+This is documented because it is used by C<ExtUtils::ParseXS>,
+but it's not intended for general consumption. May be removed
+at any time.
+
+=cut
+
+sub _get_inputmap_hash {
+ my $self = shift;
+ my $lookup = $self->{input_lookup};
+ my $storage = $self->{input_section};
+
+ my %rv;
+ foreach my $xstype (keys %$lookup) {
+ $rv{$xstype} = $storage->[ $lookup->{$xstype} ]->code;
+
+ # Squash trailing whitespace to one line break
+ # This isn't strictly necessary, but makes the output more similar
+ # to the original ExtUtils::ParseXS.
+ $rv{$xstype} =~ s/\s*\z/\n/;
+ }
+
+ return \%rv;
+}
+
+
+=head2 _get_outputmap_hash
+
+Returns a hash mapping the XS types (identifiers) to the
+corresponding OUTPUT code:
+
+ {
+ 'T_CALLBACK' => ' sv_setpvn($arg, $var.context.value().chp(),
+ $var.context.value().size());
+ ',
+ 'T_OUT' => ' {
+ GV *gv = newGVgen("$Package");
+ if ( do_open(gv, "+>&", 3, FALSE, 0, 0, $var) )
+ sv_setsv(
+ $arg,
+ sv_bless(newRV((SV*)gv), gv_stashpv("$Package",1))
+ );
+ else
+ $arg = &PL_sv_undef;
+ }
+ ',
+ # ...
+ }
+
+This is documented because it is used by C<ExtUtils::ParseXS>,
+but it's not intended for general consumption. May be removed
+at any time.
+
+=cut
+
+sub _get_outputmap_hash {
+ my $self = shift;
+ my $lookup = $self->{output_lookup};
+ my $storage = $self->{output_section};
+
+ my %rv;
+ foreach my $xstype (keys %$lookup) {
+ $rv{$xstype} = $storage->[ $lookup->{$xstype} ]->code;
+
+ # Squash trailing whitespace to one line break
+ # This isn't strictly necessary, but makes the output more similar
+ # to the original ExtUtils::ParseXS.
+ $rv{$xstype} =~ s/\s*\z/\n/;
+ }
+
+ return \%rv;
+}
+
+=head2 _get_prototype_hash
+
+Returns a hash mapping the C types of the typemap to their
+corresponding prototypes.
+
+ {
+ 'char **' => '$',
+ 'bool_t' => '$',
+ 'AV *' => '$',
+ 'InputStream' => '$',
+ 'double' => '$',
+ # ...
+ }
+
+This is documented because it is used by C<ExtUtils::ParseXS>,
+but it's not intended for general consumption. May be removed
+at any time.
+
+=cut
+
+sub _get_prototype_hash {
+ my $self = shift;
+ my $lookup = $self->{typemap_lookup};
+ my $storage = $self->{typemap_section};
+
+ my %rv;
+ foreach my $ctype (keys %$lookup) {
+ $rv{$ctype} = $storage->[ $lookup->{$ctype} ]->proto || '$';
+ }
+
+ return \%rv;
+}
+
+
+
+# make sure that the provided types wouldn't collide with what's
+# in the object already.
+sub validate {
+ my $self = shift;
+ my %args = @_;
+
+ if ( exists $args{ctype}
+ and exists $self->{typemap_lookup}{_tidy_type($args{ctype})} )
+ {
+ die("Multiple definition of ctype '$args{ctype}' in TYPEMAP section");
+ }
+
+ if ( exists $args{inputmap_xstype}
+ and exists $self->{input_lookup}{$args{inputmap_xstype}} )
+ {
+ die("Multiple definition of xstype '$args{inputmap_xstype}' in INPUTMAP section");
+ }
+
+ if ( exists $args{outputmap_xstype}
+ and exists $self->{output_lookup}{$args{outputmap_xstype}} )
+ {
+ die("Multiple definition of xstype '$args{outputmap_xstype}' in OUTPUTMAP section");
+ }
+
+ return 1;
+}
+
+sub _parse {
+ my $self = shift;
+ my $stringref = shift;
+ my $lineno_offset = shift;
+ $lineno_offset = 0 if not defined $lineno_offset;
+ my $filename = shift;
+ $filename = '<string>' if not defined $filename;
+
+ my $replace = $self->{replace};
+ my $skip = $self->{skip};
+ die "Can only replace OR skip" if $replace and $skip;
+ my @add_params;
+ push @add_params, replace => 1 if $replace;
+ push @add_params, skip => 1 if $skip;
+
+ # TODO comments should round-trip, currently ignoring
+ # TODO order of sections, multiple sections of same type
+ # Heavily influenced by ExtUtils::ParseXS
+ my $section = 'typemap';
+ my $lineno = $lineno_offset;
+ my $junk = "";
+ my $current = \$junk;
+ my @input_expr;
+ my @output_expr;
+ while ($$stringref =~ /^(.*)$/gcm) {
+ local $_ = $1;
+ ++$lineno;
+ chomp;
+ next if /^\s*#/;
+ if (/^INPUT\s*$/) {
+ $section = 'input';
+ $current = \$junk;
+ next;
+ }
+ elsif (/^OUTPUT\s*$/) {
+ $section = 'output';
+ $current = \$junk;
+ next;
+ }
+ elsif (/^TYPEMAP\s*$/) {
+ $section = 'typemap';
+ $current = \$junk;
+ next;
+ }
+
+ if ($section eq 'typemap') {
+ my $line = $_;
+ s/^\s+//; s/\s+$//;
+ next if $_ eq '' or /^#/;
+ my($type, $kind, $proto) = /^(.*?\S)\s+(\S+)\s*($ExtUtils::ParseXS::Constants::PrototypeRegexp*)$/o
+ or warn("Warning: File '$filename' Line $lineno '$line' TYPEMAP entry needs 2 or 3 columns\n"),
+ next;
+ # prototype defaults to '$'
+ $proto = '$' unless $proto;
+ warn("Warning: File '$filename' Line $lineno '$line' Invalid prototype '$proto'\n")
+ unless _valid_proto_string($proto);
+ $self->add_typemap(
+ ExtUtils::Typemaps::Type->new(
+ xstype => $kind, proto => $proto, ctype => $type
+ ),
+ @add_params
+ );
+ } elsif (/^\s/) {
+ s/\s+$//;
+ $$current .= $$current eq '' ? $_ : "\n".$_;
+ } elsif ($_ eq '') {
+ next;
+ } elsif ($section eq 'input') {
+ s/\s+$//;
+ push @input_expr, {xstype => $_, code => ''};
+ $current = \$input_expr[-1]{code};
+ } else { # output section
+ s/\s+$//;
+ push @output_expr, {xstype => $_, code => ''};
+ $current = \$output_expr[-1]{code};
+ }
+
+ } # end while lines
+
+ foreach my $inexpr (@input_expr) {
+ $self->add_inputmap( ExtUtils::Typemaps::InputMap->new(%$inexpr), @add_params );
+ }
+ foreach my $outexpr (@output_expr) {
+ $self->add_outputmap( ExtUtils::Typemaps::OutputMap->new(%$outexpr), @add_params );
+ }
+
+ return 1;
+}
+
+# taken from ExtUtils::ParseXS
+sub _tidy_type {
+ local $_ = shift;
+
+ # rationalise any '*' by joining them into bunches and removing whitespace
+ s#\s*(\*+)\s*#$1#g;
+ s#(\*+)# $1 #g ;
+
+ # trim leading & trailing whitespace
+ s/^\s+//; s/\s+$//;
+
+ # change multiple whitespace into a single space
+ s/\s+/ /g;
+
+ $_;
+}
+
+
+# taken from ExtUtils::ParseXS
+sub _valid_proto_string {
+ my $string = shift;
+ if ($string =~ /^$ExtUtils::ParseXS::Constants::PrototypeRegexp+$/o) {
+ return $string;
+ }
+
+ return 0 ;
+}
+
+# taken from ExtUtils::ParseXS (C_string)
+sub _escape_backslashes {
+ my $string = shift;
+ $string =~ s[\\][\\\\]g;
+ $string;
+}
+
+=head1 CAVEATS
+
+Inherits some evil code from C<ExtUtils::ParseXS>.
+
+=head1 SEE ALSO
+
+The parser is heavily inspired from the one in L<ExtUtils::ParseXS>.
+
+For details on typemaps: L<perlxstut>, L<perlxs>.
+
+=head1 AUTHOR
+
+Steffen Mueller C<<smueller@cpan.org>>
+
+=head1 COPYRIGHT & LICENSE
+
+Copyright 2009, 2010, 2011, 2012 Steffen Mueller
+
+This program is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+=cut
+
+1;
+
diff --git a/gnu/usr.bin/perl/dist/ExtUtils-ParseXS/lib/ExtUtils/Typemaps/Cmd.pm b/gnu/usr.bin/perl/dist/ExtUtils-ParseXS/lib/ExtUtils/Typemaps/Cmd.pm
new file mode 100644
index 00000000000..671110fb97a
--- /dev/null
+++ b/gnu/usr.bin/perl/dist/ExtUtils-ParseXS/lib/ExtUtils/Typemaps/Cmd.pm
@@ -0,0 +1,168 @@
+package ExtUtils::Typemaps::Cmd;
+use 5.006001;
+use strict;
+use warnings;
+our $VERSION = '3.16';
+
+use ExtUtils::Typemaps;
+
+require Exporter;
+
+our @ISA = qw(Exporter);
+our @EXPORT = qw(embeddable_typemap);
+our %EXPORT_TAGS = (all => \@EXPORT);
+
+sub embeddable_typemap {
+ my @tms = @_;
+
+ # Get typemap objects
+ my @tm_objs = map [$_, _intuit_typemap_source($_)], @tms;
+
+ # merge or short-circuit
+ my $final_tm;
+ if (@tm_objs == 1) {
+ # just one, merge would be pointless
+ $final_tm = shift(@tm_objs)->[1];
+ }
+ else {
+ # multiple, need merge
+ $final_tm = ExtUtils::Typemaps->new;
+ foreach my $other_tm (@tm_objs) {
+ my ($tm_ident, $tm_obj) = @$other_tm;
+ eval {
+ $final_tm->merge(typemap => $tm_obj);
+ 1
+ } or do {
+ my $err = $@ || 'Zombie error';
+ die "Failed to merge typ";
+ }
+ }
+ }
+
+ # stringify for embedding
+ return $final_tm->as_embedded_typemap();
+}
+
+sub _load_module {
+ my $name = shift;
+ return eval "require $name; 1";
+}
+
+SCOPE: {
+ my %sources = (
+ module => sub {
+ my $ident = shift;
+ my $tm;
+ if (/::/) { # looks like FQ module name, try that first
+ foreach my $module ($ident, "ExtUtils::Typemaps::$ident") {
+ if (_load_module($module)) {
+ eval { $tm = $module->new }
+ and return $tm;
+ }
+ }
+ }
+ else {
+ foreach my $module ("ExtUtils::Typemaps::$ident", "$ident") {
+ if (_load_module($module)) {
+ eval { $tm = $module->new }
+ and return $tm;
+ }
+ }
+ }
+ return();
+ },
+ file => sub {
+ my $ident = shift;
+ return unless -e $ident and -r _;
+ return ExtUtils::Typemaps->new(file => $ident);
+ },
+ );
+ # Try to find typemap either from module or file
+ sub _intuit_typemap_source {
+ my $identifier = shift;
+
+ my @locate_attempts;
+ if ($identifier =~ /::/ || $identifier !~ /[^\w_]/) {
+ @locate_attempts = qw(module file);
+ }
+ else {
+ @locate_attempts = qw(file module);
+ }
+
+ foreach my $source (@locate_attempts) {
+ my $tm = $sources{$source}->($identifier);
+ return $tm if defined $tm;
+ }
+
+ die "Unable to find typemap for '$identifier': "
+ . "Tried to load both as file or module and failed.\n";
+ }
+} # end SCOPE
+
+=head1 NAME
+
+ExtUtils::Typemaps::Cmd - Quick commands for handling typemaps
+
+=head1 SYNOPSIS
+
+From XS:
+
+ INCLUDE_COMMAND: $^X -MExtUtils::Typemaps::Cmd \
+ -e "print embeddable_typemap(q{Excommunicated})"
+
+Loads C<ExtUtils::Typemaps::Excommunicated>, instantiates an object,
+and dumps it as an embeddable typemap for use directly in your XS file.
+
+=head1 DESCRIPTION
+
+This is a helper module for L<ExtUtils::Typemaps> for quick
+one-liners, specifically for inclusion of shared typemaps
+that live on CPAN into an XS file (see SYNOPSIS).
+
+For this reason, the following functions are exported by default:
+
+=head1 EXPORTED FUNCTIONS
+
+=head2 embeddable_typemap
+
+Given a list of identifiers, C<embeddable_typemap>
+tries to load typemaps from a file of the given name(s),
+or from a module that is an C<ExtUtils::Typemaps> subclass.
+
+Returns a string representation of the merged typemaps that can
+be included verbatim into XS. Example:
+
+ print embeddable_typemap(
+ "Excommunicated", "ExtUtils::Typemaps::Basic", "./typemap"
+ );
+
+This will try to load a module C<ExtUtils::Typemaps::Excommunicated>
+and use it as an C<ExtUtils::Typemaps> subclass. If that fails, it'll
+try loading C<Excommunicated> as a module, if that fails, it'll try to
+read a file called F<Excommunicated>. It'll work similarly for the
+second argument, but the third will be loaded as a file first.
+
+After loading all typemap files or modules, it will merge them in the
+specified order and dump the result as an embeddable typemap.
+
+=head1 SEE ALSO
+
+L<ExtUtils::Typemaps>
+
+L<perlxs>
+
+=head1 AUTHOR
+
+Steffen Mueller C<<smueller@cpan.org>>
+
+=head1 COPYRIGHT & LICENSE
+
+Copyright 2012 Steffen Mueller
+
+This program is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+=cut
+
+1;
+
diff --git a/gnu/usr.bin/perl/dist/ExtUtils-ParseXS/lib/ExtUtils/Typemaps/InputMap.pm b/gnu/usr.bin/perl/dist/ExtUtils-ParseXS/lib/ExtUtils/Typemaps/InputMap.pm
new file mode 100644
index 00000000000..9e7053f2290
--- /dev/null
+++ b/gnu/usr.bin/perl/dist/ExtUtils-ParseXS/lib/ExtUtils/Typemaps/InputMap.pm
@@ -0,0 +1,116 @@
+package ExtUtils::Typemaps::InputMap;
+use 5.006001;
+use strict;
+use warnings;
+our $VERSION = '3.16';
+
+=head1 NAME
+
+ExtUtils::Typemaps::InputMap - Entry in the INPUT section of a typemap
+
+=head1 SYNOPSIS
+
+ use ExtUtils::Typemaps;
+ ...
+ my $input = $typemap->get_input_map('T_NV');
+ my $code = $input->code();
+ $input->code("...");
+
+=head1 DESCRIPTION
+
+Refer to L<ExtUtils::Typemaps> for details.
+
+=head1 METHODS
+
+=cut
+
+=head2 new
+
+Requires C<xstype> and C<code> parameters.
+
+=cut
+
+sub new {
+ my $prot = shift;
+ my $class = ref($prot)||$prot;
+ my %args = @_;
+
+ if (!ref($prot)) {
+ if (not defined $args{xstype} or not defined $args{code}) {
+ die("Need xstype and code parameters");
+ }
+ }
+
+ my $self = bless(
+ (ref($prot) ? {%$prot} : {})
+ => $class
+ );
+
+ $self->{xstype} = $args{xstype} if defined $args{xstype};
+ $self->{code} = $args{code} if defined $args{code};
+ $self->{code} =~ s/^(?=\S)/\t/mg;
+
+ return $self;
+}
+
+=head2 code
+
+Returns or sets the INPUT mapping code for this entry.
+
+=cut
+
+sub code {
+ $_[0]->{code} = $_[1] if @_ > 1;
+ return $_[0]->{code};
+}
+
+=head2 xstype
+
+Returns the name of the XS type of the INPUT map.
+
+=cut
+
+sub xstype {
+ return $_[0]->{xstype};
+}
+
+=head2 cleaned_code
+
+Returns a cleaned-up copy of the code to which certain transformations
+have been applied to make it more ANSI compliant.
+
+=cut
+
+sub cleaned_code {
+ my $self = shift;
+ my $code = $self->code;
+
+ $code =~ s/(?:;+\s*|;*\s+)\z//s;
+
+ # Move C pre-processor instructions to column 1 to be strictly ANSI
+ # conformant. Some pre-processors are fussy about this.
+ $code =~ s/^\s+#/#/mg;
+ $code =~ s/\s*\z/\n/;
+
+ return $code;
+}
+
+=head1 SEE ALSO
+
+L<ExtUtils::Typemaps>
+
+=head1 AUTHOR
+
+Steffen Mueller C<<smueller@cpan.org>>
+
+=head1 COPYRIGHT & LICENSE
+
+Copyright 2009, 2010, 2011, 2012 Steffen Mueller
+
+This program is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+=cut
+
+1;
+
diff --git a/gnu/usr.bin/perl/dist/ExtUtils-ParseXS/lib/ExtUtils/Typemaps/OutputMap.pm b/gnu/usr.bin/perl/dist/ExtUtils-ParseXS/lib/ExtUtils/Typemaps/OutputMap.pm
new file mode 100644
index 00000000000..95cbbccf5c3
--- /dev/null
+++ b/gnu/usr.bin/perl/dist/ExtUtils-ParseXS/lib/ExtUtils/Typemaps/OutputMap.pm
@@ -0,0 +1,195 @@
+package ExtUtils::Typemaps::OutputMap;
+use 5.006001;
+use strict;
+use warnings;
+our $VERSION = '3.16';
+
+=head1 NAME
+
+ExtUtils::Typemaps::OutputMap - Entry in the OUTPUT section of a typemap
+
+=head1 SYNOPSIS
+
+ use ExtUtils::Typemaps;
+ ...
+ my $output = $typemap->get_output_map('T_NV');
+ my $code = $output->code();
+ $output->code("...");
+
+=head1 DESCRIPTION
+
+Refer to L<ExtUtils::Typemaps> for details.
+
+=head1 METHODS
+
+=cut
+
+=head2 new
+
+Requires C<xstype> and C<code> parameters.
+
+=cut
+
+sub new {
+ my $prot = shift;
+ my $class = ref($prot)||$prot;
+ my %args = @_;
+
+ if (!ref($prot)) {
+ if (not defined $args{xstype} or not defined $args{code}) {
+ die("Need xstype and code parameters");
+ }
+ }
+
+ my $self = bless(
+ (ref($prot) ? {%$prot} : {})
+ => $class
+ );
+
+ $self->{xstype} = $args{xstype} if defined $args{xstype};
+ $self->{code} = $args{code} if defined $args{code};
+ $self->{code} =~ s/^(?=\S)/\t/mg;
+
+ return $self;
+}
+
+=head2 code
+
+Returns or sets the OUTPUT mapping code for this entry.
+
+=cut
+
+sub code {
+ $_[0]->{code} = $_[1] if @_ > 1;
+ return $_[0]->{code};
+}
+
+=head2 xstype
+
+Returns the name of the XS type of the OUTPUT map.
+
+=cut
+
+sub xstype {
+ return $_[0]->{xstype};
+}
+
+=head2 cleaned_code
+
+Returns a cleaned-up copy of the code to which certain transformations
+have been applied to make it more ANSI compliant.
+
+=cut
+
+sub cleaned_code {
+ my $self = shift;
+ my $code = $self->code;
+
+ # Move C pre-processor instructions to column 1 to be strictly ANSI
+ # conformant. Some pre-processors are fussy about this.
+ $code =~ s/^\s+#/#/mg;
+ $code =~ s/\s*\z/\n/;
+
+ return $code;
+}
+
+=head2 targetable
+
+This is an obscure optimization that used to live in C<ExtUtils::ParseXS>
+directly.
+
+In a nutshell, this will check whether the output code
+involves calling C<set_iv>, C<set_uv>, C<set_nv>, C<set_pv> or C<set_pvn>
+to set the special C<$arg> placeholder to a new value
+B<AT THE END OF THE OUTPUT CODE>. If that is the case, the code is
+eligible for using the C<TARG>-related macros to optimize this.
+Thus the name of the method: C<targetable>.
+
+If the optimization can not be applied, this returns undef.
+If it can be applied, this method returns a hash reference containing
+the following information:
+
+ type: Any of the characters i, u, n, p
+ with_size: Bool indicating whether this is the sv_setpvn variant
+ what: The code that actually evaluates to the output scalar
+ what_size: If "with_size", this has the string length (as code,
+ not constant)
+
+=cut
+
+sub targetable {
+ my $self = shift;
+ return $self->{targetable} if exists $self->{targetable};
+
+ our $bal; # ()-balanced
+ $bal = qr[
+ (?:
+ (?>[^()]+)
+ |
+ \( (??{ $bal }) \)
+ )*
+ ]x;
+
+ # matches variations on (SV*)
+ my $sv_cast = qr[
+ (?:
+ \( \s* SV \s* \* \s* \) \s*
+ )?
+ ]x;
+
+ my $size = qr[ # Third arg (to setpvn)
+ , \s* (??{ $bal })
+ ]x;
+
+ my $code = $self->code;
+
+ # We can still bootstrap compile 're', because in code re.pm is
+ # available to miniperl, and does not attempt to load the XS code.
+ use re 'eval';
+
+ my ($type, $with_size, $arg, $sarg) =
+ ($code =~
+ m[^
+ \s+
+ sv_set([iunp])v(n)? # Type, is_setpvn
+ \s*
+ \( \s*
+ $sv_cast \$arg \s* , \s*
+ ( (??{ $bal }) ) # Set from
+ ( (??{ $size }) )? # Possible sizeof set-from
+ \) \s* ; \s* $
+ ]x
+ );
+
+ my $rv = undef;
+ if ($type) {
+ $rv = {
+ type => $type,
+ with_size => $with_size,
+ what => $arg,
+ what_size => $sarg,
+ };
+ }
+ $self->{targetable} = $rv;
+ return $rv;
+}
+
+=head1 SEE ALSO
+
+L<ExtUtils::Typemaps>
+
+=head1 AUTHOR
+
+Steffen Mueller C<<smueller@cpan.org>>
+
+=head1 COPYRIGHT & LICENSE
+
+Copyright 2009, 2010, 2011, 2012 Steffen Mueller
+
+This program is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+=cut
+
+1;
+
diff --git a/gnu/usr.bin/perl/dist/ExtUtils-ParseXS/lib/ExtUtils/Typemaps/Type.pm b/gnu/usr.bin/perl/dist/ExtUtils-ParseXS/lib/ExtUtils/Typemaps/Type.pm
new file mode 100644
index 00000000000..b29e212d455
--- /dev/null
+++ b/gnu/usr.bin/perl/dist/ExtUtils-ParseXS/lib/ExtUtils/Typemaps/Type.pm
@@ -0,0 +1,121 @@
+package ExtUtils::Typemaps::Type;
+use 5.006001;
+use strict;
+use warnings;
+require ExtUtils::Typemaps;
+
+our $VERSION = '3.16';
+
+=head1 NAME
+
+ExtUtils::Typemaps::Type - Entry in the TYPEMAP section of a typemap
+
+=head1 SYNOPSIS
+
+ use ExtUtils::Typemaps;
+ ...
+ my $type = $typemap->get_type_map('char*');
+ my $input = $typemap->get_input_map($type->xstype);
+
+=head1 DESCRIPTION
+
+Refer to L<ExtUtils::Typemaps> for details.
+Object associates C<ctype> with C<xstype>, which is the index
+into the in- and output mapping tables.
+
+=head1 METHODS
+
+=cut
+
+=head2 new
+
+Requires C<xstype> and C<ctype> parameters.
+
+Optionally takes C<prototype> parameter.
+
+=cut
+
+sub new {
+ my $prot = shift;
+ my $class = ref($prot)||$prot;
+ my %args = @_;
+
+ if (!ref($prot)) {
+ if (not defined $args{xstype} or not defined $args{ctype}) {
+ die("Need xstype and ctype parameters");
+ }
+ }
+
+ my $self = bless(
+ (ref($prot) ? {%$prot} : {proto => ''})
+ => $class
+ );
+
+ $self->{xstype} = $args{xstype} if defined $args{xstype};
+ $self->{ctype} = $args{ctype} if defined $args{ctype};
+ $self->{tidy_ctype} = ExtUtils::Typemaps::_tidy_type($self->{ctype});
+ $self->{proto} = $args{'prototype'} if defined $args{'prototype'};
+
+ return $self;
+}
+
+=head2 proto
+
+Returns or sets the prototype.
+
+=cut
+
+sub proto {
+ $_[0]->{proto} = $_[1] if @_ > 1;
+ return $_[0]->{proto};
+}
+
+=head2 xstype
+
+Returns the name of the XS type that this C type is associated to.
+
+=cut
+
+sub xstype {
+ return $_[0]->{xstype};
+}
+
+=head2 ctype
+
+Returns the name of the C type as it was set on construction.
+
+=cut
+
+sub ctype {
+ return defined($_[0]->{ctype}) ? $_[0]->{ctype} : $_[0]->{tidy_ctype};
+}
+
+=head2 tidy_ctype
+
+Returns the canonicalized name of the C type.
+
+=cut
+
+sub tidy_ctype {
+ return $_[0]->{tidy_ctype};
+}
+
+=head1 SEE ALSO
+
+L<ExtUtils::Typemaps>
+
+=head1 AUTHOR
+
+Steffen Mueller C<<smueller@cpan.org>>
+
+=head1 COPYRIGHT & LICENSE
+
+Copyright 2009, 2010, 2011, 2012 Steffen Mueller
+
+This program is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+=cut
+
+1;
+
diff --git a/gnu/usr.bin/perl/dist/ExtUtils-ParseXS/lib/ExtUtils/xsubpp b/gnu/usr.bin/perl/dist/ExtUtils-ParseXS/lib/ExtUtils/xsubpp
new file mode 100644
index 00000000000..fa0cd50426a
--- /dev/null
+++ b/gnu/usr.bin/perl/dist/ExtUtils-ParseXS/lib/ExtUtils/xsubpp
@@ -0,0 +1,173 @@
+#!perl
+use 5.006;
+use strict;
+eval {
+ require ExtUtils::ParseXS;
+ ExtUtils::ParseXS->import(
+ qw(
+ process_file
+ report_error_count
+ )
+ );
+ 1;
+}
+or do {
+ my $err = $@ || 'Zombie error';
+ my $v = $ExtUtils::ParseXS::VERSION;
+ $v = '<undef>' if not defined $v;
+ die "Failed to load or import from ExtUtils::ParseXS (version $v). Please check that ExtUtils::ParseXS is installed correctly and that the newest version will be found in your \@INC path: $err";
+};
+
+use Getopt::Long;
+
+my %args = ();
+
+my $usage = "Usage: xsubpp [-v] [-csuffix csuffix] [-except] [-prototypes] [-noversioncheck] [-nolinenumbers] [-nooptimize] [-noinout] [-noargtypes] [-s pattern] [-typemap typemap]... file.xs\n";
+
+Getopt::Long::Configure qw(no_auto_abbrev no_ignore_case);
+
+@ARGV = grep {$_ ne '-C++'} @ARGV; # Allow -C++ for backward compatibility
+GetOptions(\%args, qw(hiertype!
+ prototypes!
+ versioncheck!
+ linenumbers!
+ optimize!
+ inout!
+ argtypes!
+ object_capi!
+ except!
+ v
+ typemap=s@
+ output=s
+ s=s
+ csuffix=s
+ ))
+ or die $usage;
+
+if ($args{v}) {
+ print "xsubpp version $ExtUtils::ParseXS::VERSION\n";
+ exit;
+}
+
+@ARGV == 1 or die $usage;
+
+$args{filename} = shift @ARGV;
+
+process_file(%args);
+exit( report_error_count() ? 1 : 0 );
+
+__END__
+
+=head1 NAME
+
+xsubpp - compiler to convert Perl XS code into C code
+
+=head1 SYNOPSIS
+
+B<xsubpp> [B<-v>] [B<-except>] [B<-s pattern>] [B<-prototypes>] [B<-noversioncheck>] [B<-nolinenumbers>] [B<-nooptimize>] [B<-typemap typemap>] [B<-output filename>]... file.xs
+
+=head1 DESCRIPTION
+
+This compiler is typically run by the makefiles created by L<ExtUtils::MakeMaker>
+or by L<Module::Build> or other Perl module build tools.
+
+I<xsubpp> will compile XS code into C code by embedding the constructs
+necessary to let C functions manipulate Perl values and creates the glue
+necessary to let Perl access those functions. The compiler uses typemaps to
+determine how to map C function parameters and variables to Perl values.
+
+The compiler will search for typemap files called I<typemap>. It will use
+the following search path to find default typemaps, with the rightmost
+typemap taking precedence.
+
+ ../../../typemap:../../typemap:../typemap:typemap
+
+It will also use a default typemap installed as C<ExtUtils::typemap>.
+
+=head1 OPTIONS
+
+Note that the C<XSOPT> MakeMaker option may be used to add these options to
+any makefiles generated by MakeMaker.
+
+=over 5
+
+=item B<-hiertype>
+
+Retains '::' in type names so that C++ hierarchical types can be mapped.
+
+=item B<-except>
+
+Adds exception handling stubs to the C code.
+
+=item B<-typemap typemap>
+
+Indicates that a user-supplied typemap should take precedence over the
+default typemaps. This option may be used multiple times, with the last
+typemap having the highest precedence.
+
+=item B<-output filename>
+
+Specifies the name of the output file to generate. If no file is
+specified, output will be written to standard output.
+
+=item B<-v>
+
+Prints the I<xsubpp> version number to standard output, then exits.
+
+=item B<-prototypes>
+
+By default I<xsubpp> will not automatically generate prototype code for
+all xsubs. This flag will enable prototypes.
+
+=item B<-noversioncheck>
+
+Disables the run time test that determines if the object file (derived
+from the C<.xs> file) and the C<.pm> files have the same version
+number.
+
+=item B<-nolinenumbers>
+
+Prevents the inclusion of '#line' directives in the output.
+
+=item B<-nooptimize>
+
+Disables certain optimizations. The only optimization that is currently
+affected is the use of I<target>s by the output C code (see L<perlguts>).
+This may significantly slow down the generated code, but this is the way
+B<xsubpp> of 5.005 and earlier operated.
+
+=item B<-noinout>
+
+Disable recognition of C<IN>, C<OUT_LIST> and C<INOUT_LIST> declarations.
+
+=item B<-noargtypes>
+
+Disable recognition of ANSI-like descriptions of function signature.
+
+=item B<-C++>
+
+Currently doesn't do anything at all. This flag has been a no-op for
+many versions of perl, at least as far back as perl5.003_07. It's
+allowed here for backwards compatibility.
+
+=back
+
+=head1 ENVIRONMENT
+
+No environment variables are used.
+
+=head1 AUTHOR
+
+Originally by Larry Wall. Turned into the C<ExtUtils::ParseXS> module
+by Ken Williams.
+
+=head1 MODIFICATION HISTORY
+
+See the file F<Changes>.
+
+=head1 SEE ALSO
+
+perl(1), perlxs(1), perlxstut(1), ExtUtils::ParseXS
+
+=cut
+