<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">package ExtUtils::ParseXS;
use strict;

use 5.006001;
use Cwd;
use Config;
use Exporter 'import';
use File::Basename;
use File::Spec;
use Symbol;

our $VERSION;
BEGIN {
  $VERSION = '3.51';
  require ExtUtils::ParseXS::Constants; ExtUtils::ParseXS::Constants-&gt;VERSION($VERSION);
  require ExtUtils::ParseXS::CountLines; ExtUtils::ParseXS::CountLines-&gt;VERSION($VERSION);
  require ExtUtils::ParseXS::Utilities; ExtUtils::ParseXS::Utilities-&gt;VERSION($VERSION);
  require ExtUtils::ParseXS::Eval; ExtUtils::ParseXS::Eval-&gt;VERSION($VERSION);
}
$VERSION = eval $VERSION if $VERSION =~ /_/;

use ExtUtils::ParseXS::Utilities qw(
  standard_typemap_locations
  trim_whitespace
  C_string
  valid_proto_string
  process_typemaps
  map_type
  standard_XS_defs
  assign_func_args
  analyze_preprocessor_statements
  set_cond
  Warn
  WarnHint
  current_line_number
  blurt
  death
  check_conditional_preprocessor_statements
  escape_file_for_line_directive
  report_typemap_failure
);

our @EXPORT_OK = qw(
  process_file
  report_error_count
  errors
);

##############################
# A number of "constants"
our $DIE_ON_ERROR;
our $AUTHOR_WARNINGS;
$AUTHOR_WARNINGS = ($ENV{AUTHOR_WARNINGS} || 0)
    unless defined $AUTHOR_WARNINGS;
our ($C_group_rex, $C_arg);
# Group in C (no support for comments or literals)
$C_group_rex = qr/ [({\[]
             (?: (?&gt; [^()\[\]{}]+ ) | (??{ $C_group_rex }) )*
             [)}\]] /x;
# Chunk in C without comma at toplevel (no comments):
$C_arg = qr/ (?: (?&gt; [^()\[\]{},"']+ )
       |   (??{ $C_group_rex })
       |   " (?: (?&gt; [^\\"]+ )
         |   \\.
         )* "        # String literal
              |   ' (?: (?&gt; [^\\']+ ) | \\. )* ' # Char literal
       )* /xs;

# "impossible" keyword (multiple newline)
my $END = "!End!\n\n";
# Match an XS Keyword
my $BLOCK_regexp = '\s*(' . $ExtUtils::ParseXS::Constants::XSKeywordsAlternation . "|$END)\\s*:";



sub new {
  return bless {} =&gt; shift;
}

our $Singleton = __PACKAGE__-&gt;new;

sub process_file {
  my $self;
  # Allow for $package-&gt;process_file(%hash), $obj-&gt;process_file, and process_file()
  if (@_ % 2) {
    my $invocant = shift;
    $self = ref($invocant) ? $invocant : $invocant-&gt;new;
  }
  else {
    $self = $Singleton;
  }

  my %options = @_;
  $self-&gt;{ProtoUsed} = exists $options{prototypes};

  # Set defaults.
  my %args = (
    argtypes        =&gt; 1,
    csuffix         =&gt; '.c',
    except          =&gt; 0,
    hiertype        =&gt; 0,
    inout           =&gt; 1,
    linenumbers     =&gt; 1,
    optimize        =&gt; 1,
    output          =&gt; \*STDOUT,
    prototypes      =&gt; 0,
    typemap         =&gt; [],
    versioncheck    =&gt; 1,
    FH              =&gt; Symbol::gensym(),
    die_on_error    =&gt; $DIE_ON_ERROR, # if true we die() and not exit() after errors
    author_warnings    =&gt; $AUTHOR_WARNINGS,
    %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-&gt;new(28);
  }
  @{ $self-&gt;{XSStack} } = ({type =&gt; 'none'});
  $self-&gt;{InitFileCode} = [ @ExtUtils::ParseXS::Constants::InitFileCode ];
  $self-&gt;{Overloaded}   = {}; # hashref of Package =&gt; Packid
  $self-&gt;{Fallback}     = {}; # hashref of Package =&gt; fallback setting
  $self-&gt;{errors}       = 0; # count

  # 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-&gt;{RetainCplusplusHierarchicalTypes} = $args{hiertype};
  $self-&gt;{WantPrototypes} = $args{prototypes};
  $self-&gt;{WantVersionChk} = $args{versioncheck};
  $self-&gt;{WantLineNumbers} = $args{linenumbers};
  $self-&gt;{IncludedFiles} = {};

  $self-&gt;{die_on_error} = $args{die_on_error};
  $self-&gt;{author_warnings} = $args{author_warnings};

  die "Missing required parameter 'filename'" unless $args{filename};
  $self-&gt;{filepathname} = $args{filename};
  ($self-&gt;{dir}, $self-&gt;{filename}) =
    (dirname($args{filename}), basename($args{filename}));
  $self-&gt;{filepathname} =~ s/\\/\\\\/g;
  $self-&gt;{IncludedFiles}-&gt;{$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), "&gt; $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-&gt;{dir});
  my $pwd = cwd();
  my $csuffix = $args{csuffix};

  if ($self-&gt;{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-&gt;{typemap} = process_typemaps( $args{typemap}, $pwd );

  # Move more settings from parameters to object
  foreach my $datum ( qw| argtypes except inout optimize | ) {
    $self-&gt;{$datum} = $args{$datum};
  }
  $self-&gt;{strip_c_func_prefix} = $args{s};

  # Identify the version of xsubpp used
  print &lt;&lt;EOM;
/*
 * This file was generated automatically by ExtUtils::ParseXS version $VERSION from the
 * contents of $self-&gt;{filename}. Do not edit this file, edit $self-&gt;{filename} instead.
 *
 *    ANY CHANGES MADE HERE WILL BE LOST!
 *
 */

EOM


  print("#line 1 \"" . escape_file_for_line_directive($self-&gt;{filepathname}) . "\"\n")
    if $self-&gt;{WantLineNumbers};

  # Open the input file (using $self-&gt;{filename} which
  # is a basename'd $args{filename} due to chdir above)
  open($self-&gt;{FH}, '&lt;', $self-&gt;{filename}) or die "cannot open $self-&gt;{filename}: $!\n";

  FIRSTMODULE:
  while (readline($self-&gt;{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-&gt;{filepathname}))
            if $self-&gt;{WantLineNumbers};
          next FIRSTMODULE;
        }

      } while (readline($self-&gt;{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 &amp;death won't
      # show the correct line in the message either.
      die ("Error: Unterminated pod in $self-&gt;{filename}, line $podstartline\n")
        unless $self-&gt;{lastline};
    }
    last if ($self-&gt;{Package}, $self-&gt;{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'-&gt;end_marker, "\n" if $self-&gt;{WantLineNumbers};

  standard_XS_defs();

  print 'ExtUtils::ParseXS::CountLines'-&gt;end_marker, "\n" if $self-&gt;{WantLineNumbers};

  $self-&gt;{lastline}    = $_;
  $self-&gt;{lastline_no} = $.;

  my $BootCode_ref = [];
  my $XSS_work_idx = 0;
  my $cpp_next_tmp = 'XSubPPtmpAAAA';
 PARAGRAPH:
  while ($self-&gt;fetch_para()) {
    my $outlist_ref  = [];
    # Print initial preprocessor statements and blank lines
    while (@{ $self-&gt;{line} } &amp;&amp; $self-&gt;{line}-&gt;[0] !~ /^[^\#]/) {
      my $ln = shift(@{ $self-&gt;{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-&gt;{line} };

    if ($XSS_work_idx &amp;&amp; !$self-&gt;{XSStack}-&gt;[$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-&gt;{InitFileCode} }, "#if $cpp_next_tmp\n");
      push(@{ $BootCode_ref },     "#if $cpp_next_tmp");
      $self-&gt;{XSStack}-&gt;[$XSS_work_idx]{varname} = $cpp_next_tmp++;
    }

    $self-&gt;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-&gt;{line}-&gt;[0] =~ /^\s/;

    # initialize info arrays
    foreach my $member (qw(args_match var_types defaults arg_list
                           argtype_seen in_out lengthof))
    {
      $self-&gt;{$member} = {};
    }
    $self-&gt;{proto_arg} = [];
    $self-&gt;{processing_arg_with_types} = 0; # bool
    $self-&gt;{proto_in_this_xsub}        = 0; # counter &amp; bool
    $self-&gt;{scope_in_this_xsub}        = 0; # counter &amp; bool
    $self-&gt;{interface}                 = 0; # bool
    $self-&gt;{interface_macro}           = 'XSINTERFACE_FUNC';
    $self-&gt;{interface_macro_set}       = 'XSINTERFACE_FUNC_SET';
    $self-&gt;{ProtoThisXSUB}             = $self-&gt;{WantPrototypes}; # states 0 (none), 1 (yes), 2 (empty prototype)
    $self-&gt;{ScopeThisXSUB}             = 0; # bool
    $self-&gt;{OverloadsThisXSUB}         = {}; # overloaded operators (as hash keys, to de-dup)

    my $xsreturn = 0;

    $_ = shift(@{ $self-&gt;{line} });
    while (my $kwd = $self-&gt;check_keyword("REQUIRE|PROTOTYPES|EXPORT_XSUB_SYMBOLS|FALLBACK|VERSIONCHECK|INCLUDE(?:_COMMAND)?|SCOPE")) {
      my $method = $kwd . "_handler";
      $self-&gt;$method($_);
      next PARAGRAPH unless @{ $self-&gt;{line} };
      $_ = shift(@{ $self-&gt;{line} });
    }

    if ($self-&gt;check_keyword("BOOT")) {
      check_conditional_preprocessor_statements($self);
      push (@{ $BootCode_ref }, "#line $self-&gt;{line_no}-&gt;[@{ $self-&gt;{line_no} } - @{ $self-&gt;{line} }] \""
                                . escape_file_for_line_directive($self-&gt;{filepathname}) . "\"")
        if $self-&gt;{WantLineNumbers} &amp;&amp; $self-&gt;{line}-&gt;[0] !~ /^\s*#\s*line\b/;
      push (@{ $BootCode_ref }, @{ $self-&gt;{line} }, "");
      next PARAGRAPH;
    }

    # extract return type, function name and arguments
    ($self-&gt;{ret_type}) = ExtUtils::Typemaps::tidy_type($_);
    my $RETVAL_no_return = 1 if $self-&gt;{ret_type} =~ s/^NO_OUTPUT\s+//;

    # Allow one-line ANSI-like declaration
    unshift @{ $self-&gt;{line} }, $2
      if $self-&gt;{argtypes}
        and $self-&gt;{ret_type} =~ s/^(.*?\w.*?)\s*\b(\w+\s*\(.*)/$1/s;

    # a function definition needs at least 2 lines
    $self-&gt;blurt("Error: Function definition too short '$self-&gt;{ret_type}'"), next PARAGRAPH
      unless @{ $self-&gt;{line} };

    my $externC = 1 if $self-&gt;{ret_type} =~ s/^extern "C"\s+//;
    my $static  = 1 if $self-&gt;{ret_type} =~ s/^static\s+//;

    my $func_header = shift(@{ $self-&gt;{line} });
    $self-&gt;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, $self-&gt;{func_name}, $orig_args) =  ($1, $2, $3);
    $class = "$4 $class" if $4;
    ($self-&gt;{pname} = $self-&gt;{func_name}) =~ s/^($self-&gt;{Prefix})?/$self-&gt;{Packprefix}/;
    my $clean_func_name;
    ($clean_func_name = $self-&gt;{func_name}) =~ s/^$self-&gt;{Prefix}//;
    $self-&gt;{Full_func_name} = "$self-&gt;{Packid}_$clean_func_name";
    if ($Is_VMS) {
      $self-&gt;{Full_func_name} = $SymSet-&gt;addsym( $self-&gt;{Full_func_name} );
    }

    # Check for duplicate function definition
    for my $tmp (@{ $self-&gt;{XSStack} }) {
      next unless defined $tmp-&gt;{functions}{ $self-&gt;{Full_func_name} };
      Warn( $self, "Warning: duplicate function definition '$clean_func_name' detected");
      last;
    }
    $self-&gt;{XSStack}-&gt;[$XSS_work_idx]{functions}{ $self-&gt;{Full_func_name} }++;
    delete $self-&gt;{XsubAliases};
    delete $self-&gt;{XsubAliasValues};
    %{ $self-&gt;{Interfaces} }      = ();
    @{ $self-&gt;{Attributes} }      = ();
    $self-&gt;{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-&gt;{argtypes} and $orig_args =~ /\S/) {
      my $args = "$orig_args ,";
      use re 'eval';
      if ($args =~ /^( (??{ $C_arg }) , )* $ /x) {
        @args = ($args =~ /\G ( (??{ $C_arg }) ) , /xg);
        no re 'eval';
        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) &amp;&amp; length($pre);
          my $out_type = '';
          my $inout_var;
          if ($self-&gt;{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-&gt;{argtype_seen}-&gt;{$len_name}++;
            $_ = "$len_name$default"; # Assigns to @args
          }
          $only_C_inlist_ref-&gt;{$_} = 1 if $out_type eq "OUTLIST" or $islength;
          push @{ $outlist_ref }, $len_name if $out_type =~ /OUTLIST$/;
          $self-&gt;{in_out}-&gt;{$len_name} = $out_type if $out_type;
        }
      }
      else {
        no re 'eval';
        @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-&gt;{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-&gt;{$_} = 1 if $out_type eq "OUTLIST";
          if ($out_type =~ /OUTLIST$/) {
              push @{ $outlist_ref }, undef;
          }
          $self-&gt;{in_out}-&gt;{$_} = $out_type;
        }
      }
    }
    if (defined($class)) {
      my $arg0 = ((defined($static) or $self-&gt;{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 '' &amp;&amp; $i == $#args) {
          $report_args .= ", ...";
          pop(@args);
          last;
        }
      }
      if ($only_C_inlist_ref-&gt;{$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-&gt;{defaults}-&gt;{$args[$i]} = $2;
        $self-&gt;{defaults}-&gt;{$args[$i]} =~ s/"/\\"/g;
      }
      $self-&gt;{proto_arg}-&gt;[$i+1] = '$' unless $only_C_inlist_ref-&gt;{$args[$i]};
    }
    my $min_args = $num_args - $extra_args;
    $report_args =~ s/"/\\"/g;
    $report_args =~ s/^,\s+//;
    $self-&gt;{func_args} = assign_func_args($self, \@args, $class);
    @{ $self-&gt;{args_match} }{@args} = @args_num;

    my $PPCODE = grep(/^\s*PPCODE\s*:/, @{ $self-&gt;{line} });
    my $CODE = grep(/^\s*CODE\s*:/, @{ $self-&gt;{line} });
    # Detect CODE: blocks which use ST(n)= or XST_m*(n,v)
    # to set explicit return values.
    my $EXPLICIT_RETURN = ($CODE &amp;&amp;
            ("@{ $self-&gt;{line} }" =~ /(\bST\s*\([^;]*=) | (\bXST_m\w+\s*\()/x ));

    $self-&gt;{ALIAS}  = grep(/^\s*ALIAS\s*:/,  @{ $self-&gt;{line} });

    my $INTERFACE  = grep(/^\s*INTERFACE\s*:/,  @{ $self-&gt;{line} });

    $xsreturn = 1 if $EXPLICIT_RETURN;

    $externC = $externC ? qq[extern "C"] : "";

    # print function header
    print Q(&lt;&lt;"EOF");
#$externC
#XS_EUPXS(XS_$self-&gt;{Full_func_name}); /* prototype to pass -Wmissing-prototypes */
#XS_EUPXS(XS_$self-&gt;{Full_func_name})
#[[
#    dVAR; dXSARGS;
EOF
    print Q(&lt;&lt;"EOF") if $self-&gt;{ALIAS};
#    dXSI32;
EOF
    print Q(&lt;&lt;"EOF") if $INTERFACE;
#    dXSFUNCTION($self-&gt;{ret_type});
EOF

    $self-&gt;{cond} = set_cond($ellipsis, $min_args, $num_args);

    print Q(&lt;&lt;"EOF") if $self-&gt;{except};
#    char errbuf[1024];
#    *errbuf = '\\0';
EOF

    if($self-&gt;{cond}) {
      print Q(&lt;&lt;"EOF");
#    if ($self-&gt;{cond})
#       croak_xs_usage(cv,  "$report_args");
EOF
    }
    else {
    # cv and items likely to be unused
    print Q(&lt;&lt;"EOF");
#    PERL_UNUSED_VAR(cv); /* -W */
#    PERL_UNUSED_VAR(items); /* -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(&lt;&lt;"EOF") if $PPCODE;
#    PERL_UNUSED_VAR(ax); /* -Wall */
EOF

    print Q(&lt;&lt;"EOF") if $PPCODE;
#    SP -= items;
EOF

    # Now do a block of some sort.

    $self-&gt;{condnum} = 0;
    $self-&gt;{cond} = '';            # last CASE: conditional
    push(@{ $self-&gt;{line} }, "$END:");
    push(@{ $self-&gt;{line_no} }, $self-&gt;{line_no}-&gt;[-1]);
    $_ = '';
    check_conditional_preprocessor_statements();
    while (@{ $self-&gt;{line} }) {

      $self-&gt;CASE_handler($_) if $self-&gt;check_keyword("CASE");
      print Q(&lt;&lt;"EOF");
#   $self-&gt;{except} [[
EOF

      # do initialization of input variables
      $self-&gt;{thisdone} = 0;
      $self-&gt;{retvaldone} = 0;
      $self-&gt;{deferred} = "";
      %{ $self-&gt;{arg_list} } = ();
      $self-&gt;{gotRETVAL} = 0;
      $self-&gt;INPUT_handler($_);
      $self-&gt;process_keyword("INPUT|PREINIT|INTERFACE_MACRO|C_ARGS|ALIAS|ATTRS|PROTOTYPE|SCOPE|OVERLOAD");

      print Q(&lt;&lt;"EOF") if $self-&gt;{ScopeThisXSUB};
#   ENTER;
#   [[
EOF

      if (!$self-&gt;{thisdone} &amp;&amp; defined($class)) {
        if (defined($static) or $self-&gt;{func_name} eq 'new') {
          print "\tchar *";
          $self-&gt;{var_types}-&gt;{"CLASS"} = "char *";
          $self-&gt;generate_init( {
            type          =&gt; "char *",
            num           =&gt; 1,
            var           =&gt; "CLASS",
            printed_name  =&gt; undef,
          } );
        }
        else {
          print "\t" . map_type($self, "$class *");
          $self-&gt;{var_types}-&gt;{"THIS"} = "$class *";
          $self-&gt;generate_init( {
            type          =&gt; "$class *",
            num           =&gt; 1,
            var           =&gt; "THIS",
            printed_name  =&gt; undef,
          } );
        }
      }

      # These are set if OUTPUT is found and/or CODE using RETVAL
      $self-&gt;{have_OUTPUT} = $self-&gt;{have_CODE_with_RETVAL} = 0;

      my ($wantRETVAL);
      # do code
      if (/^\s*NOT_IMPLEMENTED_YET/) {
        print "\n\tPerl_croak(aTHX_ \"$self-&gt;{pname}: not implemented yet\");\n";
        $_ = '';
      }
      else {
        if ($self-&gt;{ret_type} ne "void") {
          print "\t" . map_type($self, $self-&gt;{ret_type}, 'RETVAL') . ";\n"
            if !$self-&gt;{retvaldone};
          $self-&gt;{args_match}-&gt;{"RETVAL"} = 0;
          $self-&gt;{var_types}-&gt;{"RETVAL"} = $self-&gt;{ret_type};
          my $outputmap = $self-&gt;{typemap}-&gt;get_outputmap( ctype =&gt; $self-&gt;{ret_type} );
          print "\tdXSTARG;\n"
            if $self-&gt;{optimize} and $outputmap and $outputmap-&gt;targetable;
        }

        if (@fake_INPUT or @fake_INPUT_pre) {
          unshift @{ $self-&gt;{line} }, @fake_INPUT_pre, @fake_INPUT, $_;
          $_ = "";
          $self-&gt;{processing_arg_with_types} = 1;
          $self-&gt;INPUT_handler($_);
        }
        print $self-&gt;{deferred};

        $self-&gt;process_keyword("INIT|ALIAS|ATTRS|PROTOTYPE|INTERFACE_MACRO|INTERFACE|C_ARGS|OVERLOAD");

        if ($self-&gt;check_keyword("PPCODE")) {
          $self-&gt;print_section();
          $self-&gt;death("PPCODE must be last thing") if @{ $self-&gt;{line} };
          print "\tLEAVE;\n" if $self-&gt;{ScopeThisXSUB};
          print "#if defined(__HP_cc) || defined(__HP_aCC)\n",
                "#pragma diag_suppress 2111\n",
                "#endif\n"
            if $^O eq "hpux";
          print "\tPUTBACK;\n\treturn;\n";
          print "#if defined(__HP_cc) || defined(__HP_aCC)\n",
                "#pragma diag_default 2111\n",
                "#endif\n"
            if $^O eq "hpux";

        }
        elsif ($self-&gt;check_keyword("CODE")) {
          my $consumed_code = $self-&gt;print_section();
          if ($consumed_code =~ /\bRETVAL\b/) {
            $self-&gt;{have_CODE_with_RETVAL} = 1;
          }
        }
        elsif (defined($class) and $self-&gt;{func_name} eq "DESTROY") {
          print "\n\t";
          print "delete THIS;\n";
        }
        else {
          print "\n\t";
          if ($self-&gt;{ret_type} ne "void") {
            print "RETVAL = ";
            $wantRETVAL = 1;
          }
          if (defined($static)) {
            if ($self-&gt;{func_name} eq 'new') {
              $self-&gt;{func_name} = "$class";
            }
            else {
              print "${class}::";
            }
          }
          elsif (defined($class)) {
            if ($self-&gt;{func_name} eq 'new') {
              $self-&gt;{func_name} .= " $class";
            }
            else {
              print "THIS-&gt;";
            }
          }
          my $strip = $self-&gt;{strip_c_func_prefix};
          $self-&gt;{func_name} =~ s/^\Q$strip//
            if defined $strip;
          $self-&gt;{func_name} = 'XSFUNCTION' if $self-&gt;{interface};
          print "$self-&gt;{func_name}($self-&gt;{func_args});\n";
        }
      }

      # do output variables
      $self-&gt;{gotRETVAL} = 0;        # 1 if RETVAL seen in OUTPUT section;
      undef $self-&gt;{RETVAL_code} ;    # code to set RETVAL (from OUTPUT section);
      # $wantRETVAL set if 'RETVAL =' autogenerated
      ($wantRETVAL, $self-&gt;{ret_type}) = (0, 'void') if $RETVAL_no_return;
      undef %{ $self-&gt;{outargs} };

      $self-&gt;process_keyword("POSTCALL|OUTPUT|ALIAS|ATTRS|PROTOTYPE|OVERLOAD");

      # A CODE section with RETVAL, but no OUTPUT? FAIL!
      if ($self-&gt;{have_CODE_with_RETVAL} and not $self-&gt;{have_OUTPUT} and $self-&gt;{ret_type} ne 'void') {
        $self-&gt;Warn("Warning: Found a 'CODE' section which seems to be using 'RETVAL' but no 'OUTPUT' section.");
      }

      $self-&gt;generate_output( {
        type        =&gt; $self-&gt;{var_types}-&gt;{$_},
        num         =&gt; $self-&gt;{args_match}-&gt;{$_},
        var         =&gt; $_,
        do_setmagic =&gt; $self-&gt;{DoSetMagic},
        do_push     =&gt; undef,
      } ) for grep $self-&gt;{in_out}-&gt;{$_} =~ /OUT$/, sort keys %{ $self-&gt;{in_out} };

      my $outlist_count = @{ $outlist_ref };
      if ($outlist_count) {
        my $ext = $outlist_count;
        ++$ext if $self-&gt;{gotRETVAL} || $wantRETVAL;
        print "\tXSprePUSH;";
        print "\tEXTEND(SP,$ext);\n";
      }
      # all OUTPUT done, so now push the return value on the stack
      if ($self-&gt;{gotRETVAL} &amp;&amp; $self-&gt;{RETVAL_code}) {
        print "\t$self-&gt;{RETVAL_code}\n";
        print "\t++SP;\n" if $outlist_count;
      }
      elsif ($self-&gt;{gotRETVAL} || $wantRETVAL) {
        my $outputmap = $self-&gt;{typemap}-&gt;get_outputmap( ctype =&gt; $self-&gt;{ret_type} );
        my $trgt = $self-&gt;{optimize} &amp;&amp; $outputmap &amp;&amp; $outputmap-&gt;targetable;
        my $var = 'RETVAL';
        my $type = $self-&gt;{ret_type};

        if ($trgt) {
          my $what = $self-&gt;eval_output_typemap_code(
            qq("$trgt-&gt;{what}"),
            {var =&gt; $var, type =&gt; $self-&gt;{ret_type}}
          );
          if (not $trgt-&gt;{with_size} and $trgt-&gt;{type} eq 'p') { # sv_setpv
            # PUSHp corresponds to sv_setpvn.  Treat sv_setpv directly
              print "\tsv_setpv(TARG, $what);\n";
              print "\tXSprePUSH;\n" unless $outlist_count;
              print "\tPUSHTARG;\n";
          }
          else {
            my $tsize = $trgt-&gt;{what_size};
            $tsize = '' unless defined $tsize;
            $tsize = $self-&gt;eval_output_typemap_code(
              qq("$tsize"),
              {var =&gt; $var, type =&gt; $self-&gt;{ret_type}}
            );
            print "\tXSprePUSH;\n" unless $outlist_count;
            print "\tPUSH$trgt-&gt;{type}($what$tsize);\n";
          }
        }
        else {
          # RETVAL almost never needs SvSETMAGIC()
          $self-&gt;generate_output( {
            type        =&gt; $self-&gt;{ret_type},
            num         =&gt; 0,
            var         =&gt; 'RETVAL',
            do_setmagic =&gt; 0,
            do_push     =&gt; undef,
          } );
          print "\t++SP;\n" if $outlist_count;
        }
      }

      $xsreturn = 1 if $self-&gt;{ret_type} ne "void";
      my $num = $xsreturn;
      $xsreturn += $outlist_count;
      $self-&gt;generate_output( {
        type        =&gt; $self-&gt;{var_types}-&gt;{$_},
        num         =&gt; $num++,
        var         =&gt; $_,
        do_setmagic =&gt; 0,
        do_push     =&gt; 1,
      } ) for @{ $outlist_ref };

      # do cleanup
      $self-&gt;process_keyword("CLEANUP|ALIAS|ATTRS|PROTOTYPE|OVERLOAD");

      print Q(&lt;&lt;"EOF") if $self-&gt;{ScopeThisXSUB};
#   ]]
EOF
      print Q(&lt;&lt;"EOF") if $self-&gt;{ScopeThisXSUB} and not $PPCODE;
#   LEAVE;
EOF

      # print function trailer
      print Q(&lt;&lt;"EOF");
#    ]]
EOF
      print Q(&lt;&lt;"EOF") if $self-&gt;{except};
#    BEGHANDLERS
#    CATCHALL
#    sprintf(errbuf, "%s: %s\\tpropagated", Xname, Xreason);
#    ENDHANDLERS
EOF
      if ($self-&gt;check_keyword("CASE")) {
        $self-&gt;blurt("Error: No 'CASE:' at top of function")
          unless $self-&gt;{condnum};
        $_ = "CASE: $_";    # Restore CASE: label
        next;
      }
      last if $_ eq "$END:";
      $self-&gt;death(/^$BLOCK_regexp/o ? "Misplaced '$1:'" : "Junk at end of function ($_)");
    }

    print Q(&lt;&lt;"EOF") if $self-&gt;{except};
#    if (errbuf[0])
#    Perl_croak(aTHX_ errbuf);
EOF
    print "#if defined(__HP_cc) || defined(__HP_aCC)\n",
          "#pragma diag_suppress 2128\n",
          "#endif\n"
      if $^O eq "hpux";

    if ($xsreturn) {
      print Q(&lt;&lt;"EOF") unless $PPCODE;
#    XSRETURN($xsreturn);
EOF
    }
    else {
      print Q(&lt;&lt;"EOF") unless $PPCODE;
#    XSRETURN_EMPTY;
EOF
    }
    print "#if defined(__HP_cc) || defined(__HP_aCC)\n",
          "#pragma diag_default 2128\n",
          "#endif\n"
      if $^O eq "hpux";

    print Q(&lt;&lt;"EOF");
#]]
#
EOF

    $self-&gt;{proto} = "";
    unless($self-&gt;{ProtoThisXSUB}) {
      $self-&gt;{newXS} = "newXS_deffile";
      $self-&gt;{file} = "";
    }
    else {
    # Build the prototype string for the xsub
      $self-&gt;{newXS} = "newXSproto_portable";
      $self-&gt;{file} = ", file";

      if ($self-&gt;{ProtoThisXSUB} eq 2) {
        # User has specified empty prototype
      }
      elsif ($self-&gt;{ProtoThisXSUB} eq 1) {
        my $s = ';';
        if ($min_args &lt; $num_args)  {
          $s = '';
          $self-&gt;{proto_arg}-&gt;[$min_args] .= ";";
        }
        push @{ $self-&gt;{proto_arg} }, "$s\@"
          if $ellipsis;

        $self-&gt;{proto} = join ("", grep defined, @{ $self-&gt;{proto_arg} } );
      }
      else {
        # User has specified a prototype
        $self-&gt;{proto} = $self-&gt;{ProtoThisXSUB};
      }
      $self-&gt;{proto} = qq{, "$self-&gt;{proto}"};
    }

    if ($self-&gt;{XsubAliases} and keys %{ $self-&gt;{XsubAliases} }) {
      $self-&gt;{XsubAliases}-&gt;{ $self-&gt;{pname} } = 0
        unless defined $self-&gt;{XsubAliases}-&gt;{ $self-&gt;{pname} };
      foreach my $xname (sort keys %{ $self-&gt;{XsubAliases} }) {
        my $value = $self-&gt;{XsubAliases}{$xname};
        push(@{ $self-&gt;{InitFileCode} }, Q(&lt;&lt;"EOF"));
#        cv = $self-&gt;{newXS}(\"$xname\", XS_$self-&gt;{Full_func_name}$self-&gt;{file}$self-&gt;{proto});
#        XSANY.any_i32 = $value;
EOF
      }
    }
    elsif (@{ $self-&gt;{Attributes} }) {
      push(@{ $self-&gt;{InitFileCode} }, Q(&lt;&lt;"EOF"));
#        cv = $self-&gt;{newXS}(\"$self-&gt;{pname}\", XS_$self-&gt;{Full_func_name}$self-&gt;{file}$self-&gt;{proto});
#        apply_attrs_string("$self-&gt;{Package}", cv, "@{ $self-&gt;{Attributes} }", 0);
EOF
    }
    elsif ($self-&gt;{interface}) {
      foreach my $yname (sort keys %{ $self-&gt;{Interfaces} }) {
        my $value = $self-&gt;{Interfaces}{$yname};
        $yname = "$self-&gt;{Package}\::$yname" unless $yname =~ /::/;
        push(@{ $self-&gt;{InitFileCode} }, Q(&lt;&lt;"EOF"));
#        cv = $self-&gt;{newXS}(\"$yname\", XS_$self-&gt;{Full_func_name}$self-&gt;{file}$self-&gt;{proto});
#        $self-&gt;{interface_macro_set}(cv,$value);
EOF
      }
    }
    elsif($self-&gt;{newXS} eq 'newXS_deffile'){ # work around P5NCI's empty newXS macro
      push(@{ $self-&gt;{InitFileCode} },
       "        $self-&gt;{newXS}(\"$self-&gt;{pname}\", XS_$self-&gt;{Full_func_name}$self-&gt;{file}$self-&gt;{proto});\n");
    }
    else {
      push(@{ $self-&gt;{InitFileCode} },
       "        (void)$self-&gt;{newXS}(\"$self-&gt;{pname}\", XS_$self-&gt;{Full_func_name}$self-&gt;{file}$self-&gt;{proto});\n");
    }

    for my $operator (sort keys %{ $self-&gt;{OverloadsThisXSUB} }) {
      $self-&gt;{Overloaded}-&gt;{$self-&gt;{Package}} = $self-&gt;{Packid};
      my $overload = "$self-&gt;{Package}\::($operator";
      push(@{ $self-&gt;{InitFileCode} },
        "        (void)$self-&gt;{newXS}(\"$overload\", XS_$self-&gt;{Full_func_name}$self-&gt;{file}$self-&gt;{proto});\n");
    }
  } # END 'PARAGRAPH' 'while' loop

  for my $package (sort keys %{ $self-&gt;{Overloaded} }) { # make them findable with fetchmethod
    my $packid = $self-&gt;{Overloaded}-&gt;{$package};
    print Q(&lt;&lt;"EOF");
#XS_EUPXS(XS_${packid}_nil); /* prototype to pass -Wmissing-prototypes */
#XS_EUPXS(XS_${packid}_nil)
#{
#   dXSARGS;
#   PERL_UNUSED_VAR(items);
#   XSRETURN_EMPTY;
#}
#
EOF
    unshift(@{ $self-&gt;{InitFileCode} }, Q(&lt;&lt;"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)newXS_deffile("${package}::()", XS_${packid}_nil);
MAKE_FETCHMETHOD_WORK
  }

  # print initialization routine

  print Q(&lt;&lt;"EOF");
##ifdef __cplusplus
#extern "C" {
##endif
EOF

  print Q(&lt;&lt;"EOF");
#XS_EXTERNAL(boot_$self-&gt;{Module_cname}); /* prototype to pass -Wmissing-prototypes */
#XS_EXTERNAL(boot_$self-&gt;{Module_cname})
#[[
##if PERL_VERSION_LE(5, 21, 5)
#    dVAR; dXSARGS;
##else
#    dVAR; ${\($self-&gt;{WantVersionChk} ?
     'dXSBOOTARGSXSAPIVERCHK;' : 'dXSBOOTARGSAPIVERCHK;')}
##endif
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 $self-&gt;{Full_func_name} there are no xsubs in this .xs
  #so 'file' is unused
  print Q(&lt;&lt;"EOF") if $self-&gt;{Full_func_name};
##if PERL_VERSION_LE(5, 8, 999) /* PERL_VERSION_LT is 5.33+ */
#    char* file = __FILE__;
##else
#    const char* file = __FILE__;
##endif
#
#    PERL_UNUSED_VAR(file);
EOF

  print Q("#\n");

  print Q(&lt;&lt;"EOF");
#    PERL_UNUSED_VAR(cv); /* -W */
#    PERL_UNUSED_VAR(items); /* -W */
EOF

  if( $self-&gt;{WantVersionChk}){
    print Q(&lt;&lt;"EOF") ;
##if PERL_VERSION_LE(5, 21, 5)
#    XS_VERSION_BOOTCHECK;
##  ifdef XS_APIVERSION_BOOTCHECK
#    XS_APIVERSION_BOOTCHECK;
##  endif
##endif

EOF
  } else {
    print Q(&lt;&lt;"EOF") ;
##if PERL_VERSION_LE(5, 21, 5) &amp;&amp; defined(XS_APIVERSION_BOOTCHECK)
#  XS_APIVERSION_BOOTCHECK;
##endif

EOF
  }

  print Q(&lt;&lt;"EOF") if defined $self-&gt;{XsubAliases} or defined $self-&gt;{interfaces};
#    {
#        CV * cv;
#
EOF

  if (keys %{ $self-&gt;{Overloaded} }) {
    # once if any overloads
    print Q(&lt;&lt;"EOF");
#    /* register the overloading (type 'A') magic */
##if PERL_VERSION_LE(5, 8, 999) /* PERL_VERSION_LT is 5.33+ */
#    PL_amagic_generation++;
##endif
EOF
    for my $package (sort keys %{ $self-&gt;{Overloaded} }) {
      # once for each package with overloads
      my $fallback = $self-&gt;{Fallback}-&gt;{$package} || "&amp;PL_sv_undef";
      print Q(&lt;&lt;"EOF");
#    /* 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 ),
#        $fallback
#    );
EOF
    }
  }

  print @{ $self-&gt;{InitFileCode} };

  print Q(&lt;&lt;"EOF") if defined $self-&gt;{XsubAliases} or defined $self-&gt;{interfaces};
#    }
EOF

  if (@{ $BootCode_ref }) {
    print "\n    /* Initialisation Section */\n\n";
    @{ $self-&gt;{line} } = @{ $BootCode_ref };
    $self-&gt;print_section();
    print "\n    /* End of Initialisation Section */\n\n";
  }

  print Q(&lt;&lt;'EOF');
##if PERL_VERSION_LE(5, 21, 5)
##  if PERL_VERSION_GE(5, 9, 0)
#    if (PL_unitcheckav)
#        call_list(PL_scopestack_ix, PL_unitcheckav);
##  endif
#    XSRETURN_YES;
##else
#    Perl_xs_boot_epilog(aTHX_ ax);
##endif
#]]
#
##ifdef __cplusplus
#}
##endif
EOF

  warn("Please specify prototyping behavior for $self-&gt;{filename} (see perlxs manual)\n")
    unless $self-&gt;{ProtoUsed};

  chdir($orig_cwd);
  select($orig_fh);
  untie *PSEUDO_STDOUT if tied *PSEUDO_STDOUT;
  close $self-&gt;{FH};

  return 1;
}

sub report_error_count {
  if (@_) {
    return $_[0]-&gt;{errors}||0;
  }
  else {
    return $Singleton-&gt;{errors}||0;
  }
}
*errors = \&amp;report_error_count;

# Input:  ($self, $_, @{ $self-&gt;{line} }) == unparsed input.
# Output: ($_, @{ $self-&gt;{line} }) == (rest of line, following lines).
# Return: the matched keyword if found, otherwise 0
sub check_keyword {
  my $self = shift;
  $_ = shift(@{ $self-&gt;{line} }) while !/\S/ &amp;&amp; @{ $self-&gt;{line} };
  s/^(\s*)($_[0])\s*:\s*(?:#.*)?/$1/s &amp;&amp; $2;
}

sub print_section {
  my $self = shift;

  # the "do" is required for right semantics
  do { $_ = shift(@{ $self-&gt;{line} }) } while !/\S/ &amp;&amp; @{ $self-&gt;{line} };

  my $consumed_code = '';

  print("#line ", $self-&gt;{line_no}-&gt;[@{ $self-&gt;{line_no} } - @{ $self-&gt;{line} } -1], " \"",
        escape_file_for_line_directive($self-&gt;{filepathname}), "\"\n")
    if $self-&gt;{WantLineNumbers} &amp;&amp; !/^\s*#\s*line\b/ &amp;&amp; !/^#if XSubPPtmp/;
  for (;  defined($_) &amp;&amp; !/^$BLOCK_regexp/o;  $_ = shift(@{ $self-&gt;{line} })) {
    print "$_\n";
    $consumed_code .= "$_\n";
  }
  print 'ExtUtils::ParseXS::CountLines'-&gt;end_marker, "\n" if $self-&gt;{WantLineNumbers};

  return $consumed_code;
}

sub merge_section {
  my $self = shift;
  my $in = '';

  while (!/\S/ &amp;&amp; @{ $self-&gt;{line} }) {
    $_ = shift(@{ $self-&gt;{line} });
  }

  for (;  defined($_) &amp;&amp; !/^$BLOCK_regexp/o;  $_ = shift(@{ $self-&gt;{line} })) {
    $in .= "$_\n";
  }
  chomp $in;
  return $in;
}

sub process_keyword {
  my($self, $pattern) = @_;

  while (my $kwd = $self-&gt;check_keyword($pattern)) {
    my $method = $kwd . "_handler";
    $self-&gt;$method($_);
  }
}

sub CASE_handler {
  my $self = shift;
  $_ = shift;
  $self-&gt;blurt("Error: 'CASE:' after unconditional 'CASE:'")
    if $self-&gt;{condnum} &amp;&amp; $self-&gt;{cond} eq '';
  $self-&gt;{cond} = $_;
  trim_whitespace($self-&gt;{cond});
  print "   ", ($self-&gt;{condnum}++ ? " else" : ""), ($self-&gt;{cond} ? " if ($self-&gt;{cond})\n" : "\n");
  $_ = '';
}

sub INPUT_handler {
  my $self = shift;
  $_ = shift;
  for (;  !/^$BLOCK_regexp/o;  $_ = shift(@{ $self-&gt;{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-&gt;{lengthof}-&gt;{$2} = undef;
      $self-&gt;{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) = /^(.*?[^&amp;\s])\s*(\&amp;?)\s*\b(\w+)$/s
      or $self-&gt;blurt("Error: invalid argument declaration '$ln'"), next;

    # Check for duplicate definitions
    $self-&gt;blurt("Error: duplicate definition of argument '$var_name' ignored"), next
      if $self-&gt;{arg_list}-&gt;{$var_name}++
        or defined $self-&gt;{argtype_seen}-&gt;{$var_name} and not $self-&gt;{processing_arg_with_types};

    $self-&gt;{thisdone} |= $var_name eq "THIS";
    $self-&gt;{retvaldone} |= $var_name eq "RETVAL";
    $self-&gt;{var_types}-&gt;{$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-&gt;{var_num} = $self-&gt;{args_match}-&gt;{$var_name};

    if ($self-&gt;{var_num}) {
      my $typemap = $self-&gt;{typemap}-&gt;get_typemap(ctype =&gt; $var_type);
      $self-&gt;report_typemap_failure($self-&gt;{typemap}, $var_type, "death")
        if not $typemap and not $is_overridden_typemap;
      $self-&gt;{proto_arg}-&gt;[$self-&gt;{var_num}] = ($typemap &amp;&amp; $typemap-&gt;proto) || "\$";
    }
    $self-&gt;{func_args} =~ s/\b($var_name)\b/&amp;$1/ if $var_addr;
    if ($var_init =~ /^[=;]\s*NO_INIT\s*;?\s*$/
      or $self-&gt;{in_out}-&gt;{$var_name} and $self-&gt;{in_out}-&gt;{$var_name} =~ /^OUT/
      and $var_init !~ /\S/) {
      if ($printed_name) {
        print ";\n";
      }
      else {
        print "\t$var_name;\n";
      }
    }
    elsif ($var_init =~ /\S/) {
      $self-&gt;output_init( {
        type          =&gt; $var_type,
        num           =&gt; $self-&gt;{var_num},
        var           =&gt; $var_name,
        init          =&gt; $var_init,
        printed_name  =&gt; $printed_name,
      } );
    }
    elsif ($self-&gt;{var_num}) {
      $self-&gt;generate_init( {
        type          =&gt; $var_type,
        num           =&gt; $self-&gt;{var_num},
        var           =&gt; $var_name,
        printed_name  =&gt; $printed_name,
      } );
    }
    else {
      print ";\n";
    }
  }
}

sub OUTPUT_handler {
  my $self = shift;
  $self-&gt;{have_OUTPUT} = 1;

  $_ = shift;
  for (;  !/^$BLOCK_regexp/o;  $_ = shift(@{ $self-&gt;{line} })) {
    next unless /\S/;
    if (/^\s*SETMAGIC\s*:\s*(ENABLE|DISABLE)\s*/) {
      $self-&gt;{DoSetMagic} = ($1 eq "ENABLE" ? 1 : 0);
      next;
    }
    my ($outarg, $outcode) = /^\s*(\S+)\s*(.*?)\s*$/s;
    $self-&gt;blurt("Error: duplicate OUTPUT argument '$outarg' ignored"), next
      if $self-&gt;{outargs}-&gt;{$outarg}++;
    if (!$self-&gt;{gotRETVAL} and $outarg eq 'RETVAL') {
      # deal with RETVAL last
      $self-&gt;{RETVAL_code} = $outcode;
      $self-&gt;{gotRETVAL} = 1;
      next;
    }
    $self-&gt;blurt("Error: OUTPUT $outarg not an argument"), next
      unless defined($self-&gt;{args_match}-&gt;{$outarg});
    $self-&gt;blurt("Error: No input definition for OUTPUT argument '$outarg' - ignored"), next
      unless defined $self-&gt;{var_types}-&gt;{$outarg};
    $self-&gt;{var_num} = $self-&gt;{args_match}-&gt;{$outarg};
    if ($outcode) {
      print "\t$outcode\n";
      print "\tSvSETMAGIC(ST(" , $self-&gt;{var_num} - 1 , "));\n" if $self-&gt;{DoSetMagic};
    }
    else {
      $self-&gt;generate_output( {
        type        =&gt; $self-&gt;{var_types}-&gt;{$outarg},
        num         =&gt; $self-&gt;{var_num},
        var         =&gt; $outarg,
        do_setmagic =&gt; $self-&gt;{DoSetMagic},
        do_push     =&gt; undef,
      } );
    }
    delete $self-&gt;{in_out}-&gt;{$outarg}     # No need to auto-OUTPUT
      if exists $self-&gt;{in_out}-&gt;{$outarg} and $self-&gt;{in_out}-&gt;{$outarg} =~ /OUT$/;
  }
}

sub C_ARGS_handler {
  my $self = shift;
  $_ = shift;
  my $in = $self-&gt;merge_section();

  trim_whitespace($in);
  $self-&gt;{func_args} = $in;
}

sub INTERFACE_MACRO_handler {
  my $self = shift;
  $_ = shift;
  my $in = $self-&gt;merge_section();

  trim_whitespace($in);
  if ($in =~ /\s/) {        # two
    ($self-&gt;{interface_macro}, $self-&gt;{interface_macro_set}) = split ' ', $in;
  }
  else {
    $self-&gt;{interface_macro} = $in;
    $self-&gt;{interface_macro_set} = 'UNKNOWN_CVT'; # catch later
  }
  $self-&gt;{interface} = 1;        # local
  $self-&gt;{interfaces} = 1;        # global
}

sub INTERFACE_handler {
  my $self = shift;
  $_ = shift;
  my $in = $self-&gt;merge_section();

  trim_whitespace($in);

  foreach (split /[\s,]+/, $in) {
    my $iface_name = $_;
    $iface_name =~ s/^$self-&gt;{Prefix}//;
    $self-&gt;{Interfaces}-&gt;{$iface_name} = $_;
  }
  print Q(&lt;&lt;"EOF");
#    XSFUNCTION = $self-&gt;{interface_macro}($self-&gt;{ret_type},cv,XSANY.any_dptr);
EOF
  $self-&gt;{interface} = 1;        # local
  $self-&gt;{interfaces} = 1;        # global
}

sub CLEANUP_handler {
  my $self = shift;
  $self-&gt;print_section();
}

sub PREINIT_handler {
  my $self = shift;
  $self-&gt;print_section();
}

sub POSTCALL_handler {
  my $self = shift;
  $self-&gt;print_section();
}

sub INIT_handler {
  my $self = shift;
  $self-&gt;print_section();
}

sub get_aliases {
  my $self = shift;
  my ($line) = @_;
  my ($orig) = $line;

  # we use this later for symbolic aliases
  my $fname = $self-&gt;{Packprefix} . $self-&gt;{func_name};

  # Parse alias definitions
  # format is
  #    alias = value Pack::alias = value ...
  # or
  #    alias =&gt; other
  # or
  #    alias =&gt; Pack::other
  # or
  #    Pack::alias =&gt; Other::alias

  while ($line =~ s/^\s*([\w:]+)\s*=(&gt;?)\s*([\w:]+)\s*//) {
    my ($alias, $is_symbolic, $value) = ($1, $2, $3);
    my $orig_alias = $alias;

    blurt( $self, "Error: In alias definition for '$alias' the value may not"
                  . " contain ':' unless it is symbolic.")
        if !$is_symbolic and $value=~/:/;

    # check for optional package definition in the alias
    $alias = $self-&gt;{Packprefix} . $alias if $alias !~ /::/;

    if ($is_symbolic) {
      my $orig_value = $value;
      $value = $self-&gt;{Packprefix} . $value if $value !~ /::/;
      if (defined $self-&gt;{XsubAliases}-&gt;{$value}) {
        $value = $self-&gt;{XsubAliases}-&gt;{$value};
      } elsif ($value eq $fname) {
        $value = 0;
      } else {
        blurt( $self, "Error: Unknown alias '$value' in symbolic definition for '$orig_alias'");
      }
    }

    # check for duplicate alias name &amp; duplicate value
    my $prev_value = $self-&gt;{XsubAliases}-&gt;{$alias};
    if (defined $prev_value) {
      if ($prev_value eq $value) {
        Warn( $self, "Warning: Ignoring duplicate alias '$orig_alias'")
      } else {
        Warn( $self, "Warning: Conflicting duplicate alias '$orig_alias'"
                     . " changes definition from '$prev_value' to '$value'");
        delete $self-&gt;{XsubAliasValues}-&gt;{$prev_value}{$alias};
      }
    }

    # Check and see if this alias results in two aliases having the same
    # value, we only check non-symbolic definitions as the whole point of
    # symbolic definitions is to say we want to duplicate the value and
    # it is NOT a mistake.
    unless ($is_symbolic) {
      my @keys= sort keys %{$self-&gt;{XsubAliasValues}-&gt;{$value}||{}};
      # deal with an alias of 0, which might not be in the XsubAlias dataset
      # yet as 0 is the default for the base function ($fname)
      push @keys, $fname
        if $value eq "0" and !defined $self-&gt;{XsubAlias}{$fname};
      if (@keys and $self-&gt;{author_warnings}) {
        # We do not warn about value collisions unless author_warnings
        # are enabled. They aren't helpful to a module consumer, only
        # the module author.
        @keys= map { "'$_'" }
               map { my $copy= $_;
                     $copy=~s/^$self-&gt;{Packprefix}//;
                     $copy
                   } @keys;
        WarnHint( $self,
                  "Warning: Aliases '$orig_alias' and "
                  . join(", ", @keys)
                  . " have identical values of $value"
                  . ( $value eq "0"
                      ? " - the base function"
                      : "" ),
                  !$self-&gt;{XsubAliasValueClashHinted}++
                  ? "If this is deliberate use a symbolic alias instead."
                  : undef
        );
      }
    }

    $self-&gt;{XsubAliases}-&gt;{$alias} = $value;
    $self-&gt;{XsubAliasValues}-&gt;{$value}{$alias}++;
  }

  blurt( $self, "Error: Cannot parse ALIAS definitions from '$orig'")
    if $line;
}

sub ATTRS_handler {
  my $self = shift;
  $_ = shift;

  for (;  !/^$BLOCK_regexp/o;  $_ = shift(@{ $self-&gt;{line} })) {
    next unless /\S/;
    trim_whitespace($_);
    push @{ $self-&gt;{Attributes} }, $_;
  }
}

sub ALIAS_handler {
  my $self = shift;
  $_ = shift;

  for (;  !/^$BLOCK_regexp/o;  $_ = shift(@{ $self-&gt;{line} })) {
    next unless /\S/;
    trim_whitespace($_);
    $self-&gt;get_aliases($_) if $_;
  }
}

sub OVERLOAD_handler {
  my $self = shift;
  $_ = shift;

  for (;  !/^$BLOCK_regexp/o;  $_ = shift(@{ $self-&gt;{line} })) {
    next unless /\S/;
    trim_whitespace($_);
    while ( s/^\s*([\w:"\\)\+\-\*\/\%\&lt;\&gt;\.\&amp;\|\^\!\~\{\}\=]+)\s*//) {
      $self-&gt;{OverloadsThisXSUB}-&gt;{$1} = 1;
    }
  }
}

sub FALLBACK_handler {
  my ($self, $setting) = @_;

  # the rest of the current line should contain either TRUE,
  # FALSE or UNDEF

  trim_whitespace($setting);
  $setting = uc($setting);

  my %map = (
    TRUE =&gt; "&amp;PL_sv_yes", 1 =&gt; "&amp;PL_sv_yes",
    FALSE =&gt; "&amp;PL_sv_no", 0 =&gt; "&amp;PL_sv_no",
    UNDEF =&gt; "&amp;PL_sv_undef",
  );

  # check for valid FALLBACK value
  $self-&gt;death("Error: FALLBACK: TRUE/FALSE/UNDEF") unless exists $map{$setting};

  $self-&gt;{Fallback}-&gt;{$self-&gt;{Package}} = $map{$setting};
}


sub REQUIRE_handler {
  # the rest of the current line should contain a version number
  my ($self, $ver) = @_;

  trim_whitespace($ver);

  $self-&gt;death("Error: REQUIRE expects a version number")
    unless $ver;

  # check that the version number is of the form n.n
  $self-&gt;death("Error: REQUIRE: expected a number, got '$ver'")
    unless $ver =~ /^\d+(\.\d*)?/;

  $self-&gt;death("Error: xsubpp $ver (or better) required--this is only $VERSION.")
    unless $VERSION &gt;= $ver;
}

sub VERSIONCHECK_handler {
  # the rest of the current line should contain either ENABLE or
  # DISABLE
  my ($self, $setting) = @_;

  trim_whitespace($setting);

  # check for ENABLE/DISABLE
  $self-&gt;death("Error: VERSIONCHECK: ENABLE/DISABLE")
    unless $setting =~ /^(ENABLE|DISABLE)/i;

  $self-&gt;{WantVersionChk} = 1 if $1 eq 'ENABLE';
  $self-&gt;{WantVersionChk} = 0 if $1 eq 'DISABLE';

}

sub PROTOTYPE_handler {
  my $self = shift;
  $_ = shift;

  my $specified;

  $self-&gt;death("Error: Only 1 PROTOTYPE definition allowed per xsub")
    if $self-&gt;{proto_in_this_xsub}++;

  for (;  !/^$BLOCK_regexp/o;  $_ = shift(@{ $self-&gt;{line} })) {
    next unless /\S/;
    $specified = 1;
    trim_whitespace($_);
    if ($_ eq 'DISABLE') {
      $self-&gt;{ProtoThisXSUB} = 0;
    }
    elsif ($_ eq 'ENABLE') {
      $self-&gt;{ProtoThisXSUB} = 1;
    }
    else {
      # remove any whitespace
      s/\s+//g;
      $self-&gt;death("Error: Invalid prototype '$_'")
        unless valid_proto_string($_);
      $self-&gt;{ProtoThisXSUB} = C_string($_);
    }
  }

  # If no prototype specified, then assume empty prototype ""
  $self-&gt;{ProtoThisXSUB} = 2 unless $specified;

  $self-&gt;{ProtoUsed} = 1;
}

sub SCOPE_handler {
  # Rest of line should be either ENABLE or DISABLE
  my ($self, $setting) = @_;

  $self-&gt;death("Error: Only 1 SCOPE declaration allowed per xsub")
    if $self-&gt;{scope_in_this_xsub}++;

  trim_whitespace($setting);
  $self-&gt;death("Error: SCOPE: ENABLE/DISABLE")
      unless $setting =~ /^(ENABLE|DISABLE)\b/i;
  $self-&gt;{ScopeThisXSUB} = ( uc($1) eq 'ENABLE' );
}

sub PROTOTYPES_handler {
  # the rest of the current line should contain either ENABLE or
  # DISABLE
  my ($self, $setting) = @_;

  trim_whitespace($setting);

  # check for ENABLE/DISABLE
  $self-&gt;death("Error: PROTOTYPES: ENABLE/DISABLE")
    unless $setting =~ /^(ENABLE|DISABLE)/i;

  $self-&gt;{WantPrototypes} = 1 if $1 eq 'ENABLE';
  $self-&gt;{WantPrototypes} = 0 if $1 eq 'DISABLE';
  $self-&gt;{ProtoUsed} = 1;
}

sub EXPORT_XSUB_SYMBOLS_handler {
  # the rest of the current line should contain either ENABLE or
  # DISABLE
  my ($self, $setting) = @_;

  trim_whitespace($setting);

  # check for ENABLE/DISABLE
  $self-&gt;death("Error: EXPORT_XSUB_SYMBOLS: ENABLE/DISABLE")
    unless $setting =~ /^(ENABLE|DISABLE)/i;

  my $xs_impl = $1 eq 'ENABLE' ? 'XS_EXTERNAL' : 'XS_INTERNAL';

  print Q(&lt;&lt;"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-&gt;{XSStack} }, {
          type            =&gt; 'file',
          LastLine        =&gt; $self-&gt;{lastline},
          LastLineNo      =&gt; $self-&gt;{lastline_no},
          Line            =&gt; $self-&gt;{line},
          LineNo          =&gt; $self-&gt;{line_no},
          Filename        =&gt; $self-&gt;{filename},
          Filepathname    =&gt; $self-&gt;{filepathname},
          Handle          =&gt; $self-&gt;{FH},
          IsPipe          =&gt; scalar($self-&gt;{filename} =~ /\|\s*$/),
          %args,
         });

}

sub INCLUDE_handler {
  my $self = shift;
  $_ = shift;
  # the rest of the current line should contain a valid filename

  trim_whitespace($_);

  $self-&gt;death("INCLUDE: filename missing")
    unless $_;

  $self-&gt;death("INCLUDE: output pipe is illegal")
    if /^\s*\|/;

  # simple minded recursion detector
  $self-&gt;death("INCLUDE loop detected")
    if $self-&gt;{IncludedFiles}-&gt;{$_};

  ++$self-&gt;{IncludedFiles}-&gt;{$_} unless /\|\s*$/;

  if (/\|\s*$/ &amp;&amp; /^\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-&gt;PushXSStack();

  $self-&gt;{FH} = Symbol::gensym();

  # open the new file
  open($self-&gt;{FH}, $_) or $self-&gt;death("Cannot open '$_': $!");

  print Q(&lt;&lt;"EOF");
#
#/* INCLUDE:  Including '$_' from '$self-&gt;{filename}' */
#
EOF

  $self-&gt;{filename} = $_;
  $self-&gt;{filepathname} = ( $^O =~ /^mswin/i )
                          ? qq($self-&gt;{dir}/$self-&gt;{filename}) # See CPAN RT #61908: gcc doesn't like backslashes on win32?
                          : File::Spec-&gt;catfile($self-&gt;{dir}, $self-&gt;{filename});

  # Prime the pump by reading the first
  # non-blank line

  # skip leading blank lines
  while (readline($self-&gt;{FH})) {
    last unless /^\s*$/;
  }

  $self-&gt;{lastline} = $_;
  $self-&gt;{lastline_no} = $.;
}

sub QuoteArgs {
  my $cmd = shift;
  my @args = split /\s+/, $cmd;
  $cmd = shift @args;
  for (@args) {
    $_ = q(").$_.q(") if !/^\"/ &amp;&amp; length($_) &gt; 0;
  }
  return join (' ', ($cmd, @args));
}

# code copied from CPAN::HandleConfig::safe_quote
#  - that has doc saying leave if start/finish with same quote, but no code
# given text, will conditionally quote it to protect from shell
{
  my ($quote, $use_quote) = $^O eq 'MSWin32'
      ? (q{"}, q{"})
      : (q{"'}, q{'});
  sub _safe_quote {
      my ($self, $command) = @_;
      # Set up quote/default quote
      if (defined($command)
          and $command =~ /\s/
          and $command !~ /[$quote]/) {
          return qq{$use_quote$command$use_quote}
      }
      return $command;
  }
}

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-&gt;death("INCLUDE_COMMAND: command missing")
    unless $_;

  $self-&gt;death("INCLUDE_COMMAND: pipes are illegal")
    if /^\s*\|/ or /\|\s*$/;

  $self-&gt;PushXSStack( IsPipe =&gt; 1 );

  $self-&gt;{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
  my $X = $self-&gt;_safe_quote($^X); # quotes if has spaces
  s/^\s*\$\^X/$X/;

  # open the new file
  open ($self-&gt;{FH}, "-|", $_)
    or $self-&gt;death( $self, "Cannot run command '$_' to include its output: $!");

  print Q(&lt;&lt;"EOF");
#
#/* INCLUDE_COMMAND:  Including output of '$_' from '$self-&gt;{filename}' */
#
EOF

  $self-&gt;{filename} = $_;
  $self-&gt;{filepathname} = $self-&gt;{filename};
  #$self-&gt;{filepathname} =~ s/\"/\\"/g; # Fails? See CPAN RT #53938: MinGW Broken after 2.21
  $self-&gt;{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-&gt;{FH})) {
    last unless /^\s*$/;
  }

  $self-&gt;{lastline} = $_;
  $self-&gt;{lastline_no} = $.;
}

sub PopFile {
  my $self = shift;

  return 0 unless $self-&gt;{XSStack}-&gt;[-1]{type} eq 'file';

  my $data     = pop @{ $self-&gt;{XSStack} };
  my $ThisFile = $self-&gt;{filename};
  my $isPipe   = $data-&gt;{IsPipe};

  --$self-&gt;{IncludedFiles}-&gt;{$self-&gt;{filename}}
    unless $isPipe;

  close $self-&gt;{FH};

  $self-&gt;{FH}         = $data-&gt;{Handle};
  # $filename is the leafname, which for some reason is used for diagnostic
  # messages, whereas $filepathname is the full pathname, and is used for
  # #line directives.
  $self-&gt;{filename}   = $data-&gt;{Filename};
  $self-&gt;{filepathname} = $data-&gt;{Filepathname};
  $self-&gt;{lastline}   = $data-&gt;{LastLine};
  $self-&gt;{lastline_no} = $data-&gt;{LastLineNo};
  @{ $self-&gt;{line} }       = @{ $data-&gt;{Line} };
  @{ $self-&gt;{line_no} }    = @{ $data-&gt;{LineNo} };

  if ($isPipe and $? ) {
    --$self-&gt;{lastline_no};
    print STDERR "Error reading from pipe '$ThisFile': $! in $self-&gt;{filename}, line $self-&gt;{lastline_no}\n" ;
    exit 1;
  }

  print Q(&lt;&lt;"EOF");
#
#/* INCLUDE: Returning to '$self-&gt;{filename}' from '$ThisFile' */
#
EOF

  return 1;
}

sub Q {
  my($text) = @_;
  $text =~ s/^#//gm;
  $text =~ s/\[\[/{/g;
  $text =~ s/\]\]/}/g;
  $text;
}

# Process "MODULE = Foo ..." lines and update global state accordingly
sub _process_module_xs_line {
  my ($self, $module, $pkg, $prefix) = @_;

  ($self-&gt;{Module_cname} = $module) =~ s/\W/_/g;

  $self-&gt;{Package} = defined($pkg) ? $pkg : '';
  $self-&gt;{Prefix}  = quotemeta( defined($prefix) ? $prefix : '' );

  ($self-&gt;{Packid} = $self-&gt;{Package}) =~ tr/:/_/;

  $self-&gt;{Packprefix} = $self-&gt;{Package};
  $self-&gt;{Packprefix} .= "::" if $self-&gt;{Packprefix} ne "";

  $self-&gt;{lastline} = "";
}

# Skip any embedded POD sections
sub _maybe_skip_pod {
  my ($self) = @_;

  while ($self-&gt;{lastline} =~ /^=/) {
    while ($self-&gt;{lastline} = readline($self-&gt;{FH})) {
      last if ($self-&gt;{lastline} =~ /^=cut\s*$/);
    }
    $self-&gt;death("Error: Unterminated pod") unless defined $self-&gt;{lastline};
    $self-&gt;{lastline} = readline($self-&gt;{FH});
    chomp $self-&gt;{lastline};
    $self-&gt;{lastline} =~ s/^\s+$//;
  }
}

# This chunk of code strips out (and parses) embedded TYPEMAP blocks
# which support a HEREdoc-alike block syntax.
sub _maybe_parse_typemap_block {
  my ($self) = @_;

  # This is special cased from the usual paragraph-handler logic
  # due to the HEREdoc-ish syntax.
  if ($self-&gt;{lastline} =~ /^TYPEMAP\s*:\s*&lt;&lt;\s*(?:(["'])(.+?)\1|([^\s'"]+?))\s*;?\s*$/)
  {
    my $end_marker = quotemeta(defined($1) ? $2 : $3);

    # Scan until we find $end_marker alone on a line.
    my @tmaplines;
    while (1) {
      $self-&gt;{lastline} = readline($self-&gt;{FH});
      $self-&gt;death("Error: Unterminated TYPEMAP section") if not defined $self-&gt;{lastline};
      last if $self-&gt;{lastline} =~ /^$end_marker\s*$/;
      push @tmaplines, $self-&gt;{lastline};
    }

    my $tmap = ExtUtils::Typemaps-&gt;new(
      string        =&gt; join("", @tmaplines),
      lineno_offset =&gt; 1 + ($self-&gt;current_line_number() || 0),
      fake_filename =&gt; $self-&gt;{filename},
    );
    $self-&gt;{typemap}-&gt;merge(typemap =&gt; $tmap, replace =&gt; 1);

    $self-&gt;{lastline} = "";
  }
}

# Read next xsub into @{ $self-&gt;{line} } from ($lastline, readline($self-&gt;{FH})).
sub fetch_para {
  my $self = shift;

  # parse paragraph
  $self-&gt;death("Error: Unterminated '#if/#ifdef/#ifndef'")
    if !defined $self-&gt;{lastline} &amp;&amp; $self-&gt;{XSStack}-&gt;[-1]{type} eq 'if';
  @{ $self-&gt;{line} } = ();
  @{ $self-&gt;{line_no} } = ();
  return $self-&gt;PopFile() if not defined $self-&gt;{lastline}; # EOF

  if ($self-&gt;{lastline} =~
      /^MODULE\s*=\s*([\w:]+)(?:\s+PACKAGE\s*=\s*([\w:]+))?(?:\s+PREFIX\s*=\s*(\S+))?\s*$/)
  {
    $self-&gt;_process_module_xs_line($1, $2, $3);
  }

  # count how many #ifdef levels we see in this paragraph
  # decrementing when we see an endif. if we see an elsif
  # or endif without a corresponding #ifdef then we dont
  # consider it part of this paragraph.
  my $if_level = 0;
  for (;;) {
    $self-&gt;_maybe_skip_pod;

    $self-&gt;_maybe_parse_typemap_block;

    my $final;
    if ($self-&gt;{lastline} !~ /^\s*#/ # not a CPP directive
        # 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-&gt;{lastline} =~ /^\#[ \t]*
                                  (?:
                                        (?:if|ifn?def|elif|else|endif|elifn?def|
                                           define|undef|pragma|error|
                                           warning|line\s+\d+|ident)
                                        \b
                                      | (?:include(?:_next)?|import)
                                        \s* ["&lt;] .* [&gt;"]
                                 )
                                /x
    )
    {
      last if $self-&gt;{lastline} =~ /^\S/ &amp;&amp; @{ $self-&gt;{line} } &amp;&amp; $self-&gt;{line}-&gt;[-1] eq "";
      if ($self-&gt;{lastline}=~/^#[ \t]*(if|ifn?def|elif|else|endif|elifn?def)\b/) {
        my $type = $1; # highest defined capture buffer, "if" for any if like condition
        if ($type =~ /^if/) {
          if (@{$self-&gt;{line}}) {
            # increment level
            $if_level++;
          } else {
            $final = 1;
          }
        } elsif ($type eq "endif") {
          if ($if_level) { # are we in an if that was started in this paragraph?
            $if_level--;   # yep- so decrement to end this if block
          } else {
            $final = 1;
          }
        } elsif (!$if_level) {
          # not in an #ifdef from this paragraph, thus
          # this directive should not be part of this paragraph.
          $final = 1;
        }
      }
      if ($final and @{$self-&gt;{line}}) {
        return 1;
      }

      push(@{ $self-&gt;{line} }, $self-&gt;{lastline});
      push(@{ $self-&gt;{line_no} }, $self-&gt;{lastline_no});
    }

    # Read next line and continuation lines
    last unless defined($self-&gt;{lastline} = readline($self-&gt;{FH}));
    $self-&gt;{lastline_no} = $.;
    my $tmp_line;
    $self-&gt;{lastline} .= $tmp_line
      while ($self-&gt;{lastline} =~ /\\$/ &amp;&amp; defined($tmp_line = readline($self-&gt;{FH})));

    chomp $self-&gt;{lastline};
    $self-&gt;{lastline} =~ s/^\s+$//;
    if ($final) {
      last;
    }
  }

  # Nuke trailing "line" entries until there's one that's not empty
  pop(@{ $self-&gt;{line} }), pop(@{ $self-&gt;{line_no} })
    while @{ $self-&gt;{line} } &amp;&amp; $self-&gt;{line}-&gt;[-1] eq "";

  return 1;
}

sub output_init {
  my $self = shift;
  my $argsref = shift;

  my ($type, $num, $var, $init, $printed_name)
    = @{$argsref}{qw(type num var init printed_name)};

  # local assign for efficiently passing in to eval_input_typemap_code
  local $argsref-&gt;{arg} = $num
                          ? "ST(" . ($num-1) . ")"
                          : "/* not a parameter */";

  if ( $init =~ /^=/ ) {
    if ($printed_name) {
      $self-&gt;eval_input_typemap_code(qq/print " $init\\n"/, $argsref);
    }
    else {
      $self-&gt;eval_input_typemap_code(qq/print "\\t$var $init\\n"/, $argsref);
    }
  }
  else {
    if (  $init =~ s/^\+//  &amp;&amp;  $num  ) {
      $self-&gt;generate_init( {
        type          =&gt; $type,
        num           =&gt; $num,
        var           =&gt; $var,
        printed_name  =&gt; $printed_name,
      } );
    }
    elsif ($printed_name) {
      print ";\n";
      $init =~ s/^;//;
    }
    else {
      $self-&gt;eval_input_typemap_code(qq/print "\\t$var;\\n"/, $argsref);
      $init =~ s/^;//;
    }
    $self-&gt;{deferred}
      .= $self-&gt;eval_input_typemap_code(qq/"\\n\\t$init\\n"/, $argsref);
  }
}

sub generate_init {
  my $self = shift;
  my $argsref = shift;

  my ($type, $num, $var, $printed_name)
    = @{$argsref}{qw(type num var printed_name)};

  my $argoff = $num - 1;
  my $arg = "ST($argoff)";

  my $typemaps = $self-&gt;{typemap};

  $type = ExtUtils::Typemaps::tidy_type($type);
  if (not $typemaps-&gt;get_typemap(ctype =&gt; $type)) {
    $self-&gt;report_typemap_failure($typemaps, $type);
    return;
  }

  (my $ntype = $type) =~ s/\s*\*/Ptr/g;
  (my $subtype = $ntype) =~ s/(?:Array)?(?:Ptr)?$//;

  my $typem = $typemaps-&gt;get_typemap(ctype =&gt; $type);
  my $xstype = $typem-&gt;xstype;
  #this is an optimization from perl 5.0 alpha 6, class check is skipped
  #T_REF_IV_REF is missing since it has no untyped analog at the moment
  $xstype =~ s/OBJ$/REF/ || $xstype =~ s/^T_REF_IV_PTR$/T_PTRREF/
    if $self-&gt;{func_name} =~ /DESTROY$/;
  if ($xstype eq 'T_PV' and exists $self-&gt;{lengthof}-&gt;{$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-&gt;{defaults}-&gt;{$var};
    return;
  }
  $type =~ tr/:/_/ unless $self-&gt;{RetainCplusplusHierarchicalTypes};

  my $inputmap = $typemaps-&gt;get_inputmap(xstype =&gt; $xstype);
  if (not defined $inputmap) {
    $self-&gt;blurt("Error: No INPUT definition for type '$type', typekind '$xstype' found");
    return;
  }

  my $expr = $inputmap-&gt;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-&gt;get_typemap(ctype =&gt; $subtype);
    if (not $subtypemap) {
      $self-&gt;report_typemap_failure($typemaps, $subtype);
      return;
    }

    my $subinputmap = $typemaps-&gt;get_inputmap(xstype =&gt; $subtypemap-&gt;xstype);
    if (not $subinputmap) {
      $self-&gt;blurt("Error: No INPUT definition for type '$subtype', typekind '" . $subtypemap-&gt;xstype . "' found");
      return;
    }

    my $subexpr = $subinputmap-&gt;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-&gt;{ScopeThisXSUB} = 1;
  }

  my $eval_vars = {
    var           =&gt; $var,
    printed_name  =&gt; $printed_name,
    type          =&gt; $type,
    ntype         =&gt; $ntype,
    subtype       =&gt; $subtype,
    num           =&gt; $num,
    arg           =&gt; $arg,
    argoff        =&gt; $argoff,
  };

  if (defined($self-&gt;{defaults}-&gt;{$var})) {
    $expr =~ s/(\t+)/$1    /g;
    $expr =~ s/        /\t/g;
    if ($printed_name) {
      print ";\n";
    }
    else {
      $self-&gt;eval_input_typemap_code(qq/print "\\t$var;\\n"/, $eval_vars);
    }
    if ($self-&gt;{defaults}-&gt;{$var} eq 'NO_INIT') {
      $self-&gt;{deferred} .= $self-&gt;eval_input_typemap_code(
        qq/"\\n\\tif (items &gt;= $num) {\\n$expr;\\n\\t}\\n"/,
        $eval_vars
      );
    }
    else {
      $self-&gt;{deferred} .= $self-&gt;eval_input_typemap_code(
        qq/"\\n\\tif (items &lt; $num)\\n\\t    $var = $self-&gt;{defaults}-&gt;{$var};\\n\\telse {\\n$expr;\\n\\t}\\n"/,
        $eval_vars
      );
    }
  }
  elsif ($self-&gt;{ScopeThisXSUB} or $expr !~ /^\s*\$var =/) {
    if ($printed_name) {
      print ";\n";
    }
    else {
      $self-&gt;eval_input_typemap_code(qq/print "\\t$var;\\n"/, $eval_vars);
    }
    $self-&gt;{deferred}
      .= $self-&gt;eval_input_typemap_code(qq/"\\n$expr;\\n"/, $eval_vars);
  }
  else {
    die "panic: do not know how to handle this branch for function pointers"
      if $printed_name;
    $self-&gt;eval_input_typemap_code(qq/print "$expr;\\n"/, $eval_vars);
  }
}

sub generate_output {
  my $self = shift;
  my $argsref = shift;
  my ($type, $num, $var, $do_setmagic, $do_push)
    = @{$argsref}{qw(type num var do_setmagic do_push)};

  my $arg = "ST(" . ($num - ($num != 0)) . ")";

  my $typemaps = $self-&gt;{typemap};

  $type = ExtUtils::Typemaps::tidy_type($type);
  local $argsref-&gt;{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-&gt;get_typemap(ctype =&gt; $type);
    if (not $typemap) {
      $self-&gt;report_typemap_failure($typemaps, $type);
      return;
    }

    my $outputmap = $typemaps-&gt;get_outputmap(xstype =&gt; $typemap-&gt;xstype);
    if (not $outputmap) {
      $self-&gt;blurt("Error: No OUTPUT definition for type '$type', typekind '" . $typemap-&gt;xstype . "' found");
      return;
    }

    (my $ntype = $type) =~ s/\s*\*/Ptr/g;
    $ntype =~ s/\(\)//g;
    (my $subtype = $ntype) =~ s/(?:Array)?(?:Ptr)?$//;
    $type =~ tr/:/_/ unless $self-&gt;{RetainCplusplusHierarchicalTypes};

    my $eval_vars = {%$argsref, subtype =&gt; $subtype, ntype =&gt; $ntype, arg =&gt; $arg, type =&gt; $type };
    my $expr = $outputmap-&gt;cleaned_code;
    if ($expr =~ /DO_ARRAY_ELEM/) {
      my $subtypemap = $typemaps-&gt;get_typemap(ctype =&gt; $subtype);
      if (not $subtypemap) {
        $self-&gt;report_typemap_failure($typemaps, $subtype);
        return;
      }

      my $suboutputmap = $typemaps-&gt;get_outputmap(xstype =&gt; $subtypemap-&gt;xstype);
      if (not $suboutputmap) {
        $self-&gt;blurt("Error: No OUTPUT definition for type '$subtype', typekind '" . $subtypemap-&gt;xstype . "' found");
        return;
      }

      my $subexpr = $suboutputmap-&gt;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/;
      $self-&gt;eval_output_typemap_code("print qq\a$expr\a", $eval_vars);
      print "\t\tSvSETMAGIC(ST(ix_$var));\n" if $do_setmagic;
    }
    elsif ($var eq 'RETVAL') {
      my $orig_arg = $arg;
      my $indent;
      my $use_RETVALSV = 1;
      my $do_mortal = 0;
      my $do_copy_tmp = 1;
      my $pre_expr;
      local $eval_vars-&gt;{arg} = $arg = 'RETVALSV';
      my $evalexpr = $self-&gt;eval_output_typemap_code("qq\a$expr\a", $eval_vars);

      if ($expr =~ /^\t\Q$arg\E = new/) {
        # We expect that $arg has refcnt 1, so we need to
        # mortalize it.
        $do_mortal = 1;
      }
      # If RETVAL is immortal, don't mortalize it. This code is not perfect:
      # It won't detect a func or expression that only returns immortals, for
      # example, this RE must be tried before next elsif.
      elsif ($evalexpr =~ /^\t\Q$arg\E\s*=\s*(boolSV\(|(&amp;PL_sv_yes|&amp;PL_sv_no|&amp;PL_sv_undef)\s*;)/) {
        $do_copy_tmp = 0; #$arg will be a ST(X), no SV* RETVAL, no RETVALSV
        $use_RETVALSV = 0;
      }
      elsif ($evalexpr =~ /^\s*\Q$arg\E\s*=/) {
        # We expect that $arg has refcnt &gt;=1, so we need
        # to mortalize it!
        $use_RETVALSV = 0 if $ntype eq "SVPtr";#reuse SV* RETVAL vs open new block
        $do_mortal = 1;
      }
      else {
        # Just hope that the entry would safely write it
        # over an already mortalized value. By
        # coincidence, something like $arg = &amp;PL_sv_undef
        # works too, but should be caught above.
        $pre_expr = "RETVALSV = sv_newmortal();\n";
        # new mortals don't have set magic
        $do_setmagic = 0;
      }
      if($use_RETVALSV) {
        print "\t{\n\t    SV * RETVALSV;\n";
        $indent = "\t    ";
      } else {
        $indent = "\t";
      }
      print $indent.$pre_expr if $pre_expr;

      if($use_RETVALSV) {
        #take control of 1 layer of indent, may or may not indent more
        $evalexpr =~ s/^(\t|        )/$indent/gm;
        #"\t    \t" doesn't draw right in some IDEs
        #break down all \t into spaces
        $evalexpr =~ s/\t/        /g;
        #rebuild back into \t'es, \t==8 spaces, indent==4 spaces
        $evalexpr =~ s/        /\t/g;
      }
      else {
        if($do_mortal || $do_setmagic) {
        #typemap entry evaled with RETVALSV, if we aren't using RETVALSV replace
          $evalexpr =~ s/RETVALSV/RETVAL/g; #all uses with RETVAL for prettier code
        }
        else { #if no extra boilerplate (no mortal, no set magic) is needed
            #after $evalexport, get rid of RETVALSV's visual cluter and change
          $evalexpr =~ s/RETVALSV/$orig_arg/g;#the lvalue to ST(X)
        }
      }
      #stop "	RETVAL = RETVAL;" for SVPtr type
      print $evalexpr if $evalexpr !~ /^\s*RETVAL = RETVAL;$/;
      print $indent.'RETVAL'.($use_RETVALSV ? 'SV':'')
            .' = sv_2mortal(RETVAL'.($use_RETVALSV ? 'SV':'').");\n" if $do_mortal;
      print $indent.'SvSETMAGIC(RETVAL'.($use_RETVALSV ? 'SV':'').");\n" if $do_setmagic;
      #dont do "RETVALSV = boolSV(RETVAL); ST(0) = RETVALSV;", it is visual clutter
      print $indent."$orig_arg = RETVAL".($use_RETVALSV ? 'SV':'').";\n"
        if $do_mortal || $do_setmagic || $do_copy_tmp;
      print "\t}\n" if $use_RETVALSV;
    }
    elsif ($do_push) {
      print "\tPUSHs(sv_newmortal());\n";
      local $eval_vars-&gt;{arg} = "ST($num)";
      $self-&gt;eval_output_typemap_code("print qq\a$expr\a", $eval_vars);
      print "\tSvSETMAGIC($arg);\n" if $do_setmagic;
    }
    elsif ($arg =~ /^ST\(\d+\)$/) {
      $self-&gt;eval_output_typemap_code("print qq\a$expr\a", $eval_vars);
      print "\tSvSETMAGIC($arg);\n" if $do_setmagic;
    }
  }
}


# Just delegates to a clean package.
# Shim to evaluate Perl code in the right variable context
# for typemap code (having things such as $ALIAS set up).
sub eval_output_typemap_code {
  my ($self, $code, $other) = @_;
  return ExtUtils::ParseXS::Eval::eval_output_typemap_code($self, $code, $other);
}

sub eval_input_typemap_code {
  my ($self, $code, $other) = @_;
  return ExtUtils::ParseXS::Eval::eval_input_typemap_code($self, $code, $other);
}

1;

# vim: ts=2 sw=2 et:
</pre></body></html>