xsubpp revision 7c478bd95313f5f23a4c958a745db2134aa03244
B<xsubpp> [B<-v>] [B<-C++>] [B<-except>] [B<-s pattern>] [B<-prototypes>] [B<-noversioncheck>] [B<-nolinenumbers>] [B<-nooptimize>] [B<-typemap typemap>] ... file.xs
=item B<-C++>
=item B<-v>
=item B<-nooptimize>
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.
=back
See the file F<changes.pod>.
=cut
use Cwd;
use Config;
$Is_VMS = 1;
$usage = "Usage: xsubpp [-v] [-C++] [-except] [-prototypes] [-noversioncheck] [-nolinenumbers] [-nooptimize] [-noinout] [-noargtypes] [-s pattern] [-typemap typemap]... file.xs\n";
$WantPrototypes = -1 ;
$WantVersionChk = 1 ;
$ProtoUsed = 0 ;
$WantLineNumbers = 1 ;
$WantOptimize = 1 ;
my $process_inout = 1;
my $process_argtypes = 1;
$flag =~ s/^-// ;
++ $IncludedFiles{$ARGV[0]} ;
sub TrimWhitespace
$_[0] =~ s/^\s+|\s+$//go ;
sub TidyType
my $line_no = $. + 1;
my $line = $_ ;
$type_kind{$type} = $kind ;
$$current .= $_;
$current = \$input_expr{$_};
$current = \$output_expr{$_};
$input_expr{$key} =~ s/\n+$//;
$targetable{$key} = [$t, $with_size, $arg, $sarg] if $t;
| (??{ $C_group_rex })
$line_no = 1;
my $self = shift;
$$self .= $_;
my $line = $1;
++ $line_no;
my $self = shift;
my $fmt = shift;
my $self = shift;
select PSEUDO_STDOUT;
return $in;
my $kwd ;
$cond = $_;
TrimWhitespace($cond);
for (; !/^$BLOCK_re/o; $_ = shift(@line)) {
my $line = $_ ;
my $var_init = '' ;
$var_init = $1 if s/\s*([=;+].*)$//s ;
or defined $arg_types{$var_name} and not $processing_arg_with_types;
if ($var_type =~ / \( \s* \* \s* \) /x) {
$name_printed = 1;
$name_printed = 0;
$proto_arg[$var_num] = ProtoString($var_type)
if $var_num ;
$func_args =~ s/\b($var_name)\b/&$1/ if $var_addr;
if ($var_init =~ /^[=;]\s*NO_INIT\s*;?\s*$/
and $var_init !~ /\S/) {
if ($name_printed) {
} elsif ($var_init =~ /\S/) {
&output_init($var_type, $var_num, $var_name, $var_init, $name_printed);
} elsif ($var_num) {
&generate_init($var_type, $var_num, $var_name, $name_printed);
for (; !/^$BLOCK_re/o; $_ = shift(@line)) {
if (!$gotRETVAL and $outarg eq 'RETVAL') {
$RETVAL_code = $outcode ;
$gotRETVAL = 1 ;
unless defined($args_match{$outarg});
unless defined $var_types{$outarg} ;
if ($outcode) {
&generate_output($var_types{$outarg}, $var_num, $outarg, $DoSetMagic);
my $in = merge_section();
TrimWhitespace($in);
$func_args = $in;
my $in = merge_section();
TrimWhitespace($in);
if ($in =~ /\s/) { # two
($interface_macro, $interface_macro_set) = split ' ', $in;
$interface_macro_set = 'UNKNOWN_CVT'; # catch later
$interface = 1; # local
$Interfaces = 1; # global
my $in = merge_section();
TrimWhitespace($in);
foreach (split /[\s,]+/, $in) {
$Interfaces{$_} = $_;
# XSFUNCTION = $interface_macro($ret_type,cv,XSANY.any_dptr);
$interface = 1; # local
$Interfaces = 1; # global
my ($line) = @_ ;
my ($alias) ;
my ($value) ;
while ($line =~ s/^\s*([\w:]+)\s*=\s*(\w+)\s*//) {
$alias = $1 ;
$orig_alias = $alias ;
$value = $2 ;
$alias = $Packprefix . $alias if $alias !~ /::/ ;
if defined $XsubAliases{$alias} ;
if $XsubAliasValues{$value} ;
$XsubAliases = 1;
$XsubAliases{$alias} = $value ;
if $line ;
for (; !/^$BLOCK_re/o; $_ = shift(@line)) {
for (; !/^$BLOCK_re/o; $_ = shift(@line)) {
my ($Ver) = $_ ;
TrimWhitespace($Ver) ;
unless $Ver ;
# check that the version number is of the form n.n
unless $Ver =~ /^\d+(\.\d*)?/ ;
unless $XSUBPP_version >= $Ver ;
$WantVersionChk = 1 if $1 eq 'ENABLE' ;
$WantVersionChk = 0 if $1 eq 'DISABLE' ;
my $specified ;
if $proto_in_this_xsub ++ ;
for (; !/^$BLOCK_re/o; $_ = shift(@line)) {
$specified = 1 ;
$ProtoThisXSUB = 0
$ProtoThisXSUB = 1
$ProtoThisXSUB = C_string($_) ;
$ProtoThisXSUB = 2 unless $specified ;
$ProtoUsed = 1 ;
if $scope_in_this_xsub ++ ;
for (; !/^$BLOCK_re/o; $_ = shift(@line)) {
$ScopeThisXSUB = 0
$ScopeThisXSUB = 1
$WantPrototypes = 1 if $1 eq 'ENABLE' ;
$WantPrototypes = 0 if $1 eq 'DISABLE' ;
$ProtoUsed = 1 ;
if $IncludedFiles{$_} ;
++ $IncludedFiles{$_} unless /\|\s*$/ ;
LastLine => $lastline,
LastLineNo => $lastline_no,
Filename => $filename,
Handle => $FH,
++ $FH ;
#/* INCLUDE: Including '$_' from '$filename' */
$filename = $_ ;
while (<$FH>) {
$lastline = $_ ;
$lastline_no = $. ;
return 0 unless $XSStack[-1]{type} eq 'file' ;
my $data = pop @XSStack ;
unless $isPipe ;
close $FH ;
$lastline_no = $data->{LastLineNo} ;
@line = @{ $data->{Line} } ;
@line_no = @{ $data->{LineNo} } ;
if ($isPipe and $? ) {
-- $lastline_no ;
my($string) = @_ ;
return $string ;
my($string) = @_ ;
$string =~ s[\\][\\\\]g ;
$string ;
my ($type) = @_ ;
for $cpp (@cpp) {
if ($cpp =~ /^\#\s*if/) {
$cpplevel++;
} elsif (!$cpplevel) {
$cpplevel--;
$text =~ s/\[\[/{/g;
$text =~ s/\]\]/}/g;
if $WantLineNumbers;
my $podstartline = $.;
if $WantLineNumbers;
next firstmodule
s/#if(?:def\s|\s+defined)\s*(\(__cplusplus\)|__cplusplus)/#if defined(__cplusplus) && !defined(PERL_OBJECT)/;
$lastline = $_;
$lastline_no = $.;
$Module = $1;
$lastline =~ s/^\s+$//;
$lastline =~ /^#[ \t]*(?:(?:if|ifn?def|elif|else|endif|define|undef|pragma|error|warning|line\s+\d+|ident)\b|(?:include(?:_next)?|import)\s*["<].*[>"])/) {
$lastline_no = $.;
my $tmp_line;
$lastline =~ s/^\s+$//;
my $statement = $+;
$XSS_work_idx = @XSStack;
if $XSStack[-1]{type} ne 'if';
if ($XSStack[-1]{varname}) {
if $line[0] =~ /^\s/;
$ScopeThisXSUB = 0;
$xsreturn = 0;
next PARAGRAPH ;
$RETVAL_no_return = 1 if $ret_type =~ s/^NO_OUTPUT\s+//;
next unless defined $tmp->{functions}{$Full_func_name};
last;
$DoSetMagic = 1;
my %only_outlist;
my $arg = $_;
my $default;
my $out_type;
my $inout_var;
my $type = $1;
$arg_types{$name} = $arg;
my $out_type = $1;
my $extra_args = 0;
$num_args = 0;
$elipsis = 1;
last;
$extra_args++;
$args[$i] = $1;
$report_args =~ s/^,\s+//;
s/^/&/ if $in_out{$_};
@args_match{@args} = @args_num;
$xsreturn = 1 if $EXPLICIT_RETURN;
$condnum = 0;
$thisdone = 0;
$retvaldone = 0;
$gotRETVAL = 0;
if !$retvaldone;
unshift @line, @arg_with_types, $_;
print $deferred;
$wantRETVAL = 1;
my $t = $WantOptimize && $targetable{$type_kind{$ret_type}};
warn $@ if $@;
$prepush_done = 1;
warn $@ if $@;
my $size = $t->[3];
warn $@ if $@;
$prepush_done = 1;
my $c = @outlist;
$xsreturn += $c;
print Q<<EOF if $except;
if ($xsreturn) {
print Q<<EOF unless $PPCODE;
# XSRETURN($xsreturn);
print Q<<EOF unless $PPCODE;
my $proto = "" ;
if ($ProtoThisXSUB) {
if ($ProtoThisXSUB eq 2) {
$proto = ', ""' ;
elsif ($ProtoThisXSUB ne 1) {
if $elipsis ;
$XsubAliases{$pname} = 0
unless defined $XsubAliases{$pname} ;
# cv = newXS(\"$name\", XS_$Full_func_name, file);
# sv_setpv((SV*)cv$proto) ;
# cv = newXS(\"$pname\", XS_$Full_func_name, file);
elsif ($interface) {
# cv = newXS(\"$name\", XS_$Full_func_name, file);
# $interface_macro_set(cv,$value) ;
# sv_setpv((SV*)cv$proto) ;
#XS(boot_$Module_cname)
unless $ProtoUsed ;
local($type, $num, $var, $init, $name_printed) = @_;
if( $init =~ /^=/ ) {
if ($name_printed) {
&generate_init($type, $num, $var, $name_printed);
} elsif ($name_printed) {
$init =~ s/^;//;
$init =~ s/^;//;
$errors ++
local($ntype);
local($tk);
unless defined($type_kind{$type});
$tk = $type_kind{$type};
$tk =~ s/OBJ$/REF/ if $func_name =~ /DESTROY$/;
$type =~ tr/:/_/;
unless defined $input_expr{$tk} ;
$expr = $input_expr{$tk};
if ($expr =~ /DO_ARRAY_ELEM/) {
unless defined($type_kind{$subtype});
blurt("Error: No INPUT definition for type '$subtype', typekind '$type_kind{$subtype}' found"), return
unless defined $input_expr{$type_kind{$subtype}} ;
$subexpr =~ s/\n\t/\n\t\t/g;
$expr =~ s/DO_ARRAY_ELEM/$subexpr/;
$ScopeThisXSUB = 1;
$expr =~ s/(\t+)/$1 /g;
$expr =~ s/ /\t/g;
if ($name_printed) {
$deferred .= eval qq/"\\n\\tif (items < $num)\\n\\t $var = $defaults{$var};\\n\\telse {\\n$expr;\\n\\t}\\n"/;
} elsif ($ScopeThisXSUB or $expr !~ /^\t\$var =/) {
if ($name_printed) {
if $name_printed;
local($type, $num, $var, $do_setmagic, $do_push) = @_;
local($ntype);
if ($type =~ /^array\(([^,]*),(.*)\)/) {
unless defined($type_kind{$type});
unless defined $output_expr{$type_kind{$type}} ;
$ntype =~ s/\(\)//g;
$expr = $output_expr{$type_kind{$type}};
if ($expr =~ /DO_ARRAY_ELEM/) {
unless defined($type_kind{$subtype});
blurt("Error: No OUTPUT definition for type '$subtype', typekind '$type_kind{$subtype}' found"), return
unless defined $output_expr{$type_kind{$subtype}} ;
$subexpr =~ s/\n\t/\n\t\t/g;
$expr =~ s/DO_ARRAY_ELEM\n/$subexpr/;
elsif ($var eq 'RETVAL') {
if ($expr =~ /^\t\$arg = new/) {
# We expect that $arg has refcnt 1, so we need to
elsif ($expr =~ /^\s*\$arg\s*=/) {
# We expect that $arg has refcnt >=1, so we need
# coincidence, something like $arg = &sv_undef
elsif ($do_push) {
elsif ($arg =~ /^ST\(\d+\)$/) {
$type =~ tr/:/_/;
$type =~ s/^array\(([^,]*),(.*)\).*/$1 */s;
if ($varname) {
exit ($errors ? 1 : 0);