=cut
# Global Constants
-$XSUBPP_version = "1.932";
+$XSUBPP_version = "1.937";
require 5.002;
+use vars '$cplusplus';
sub Q ;
++ $IncludedFiles{$ARGV[0]} ;
+my(@XSStack) = ({type => 'none'}); # Stack of conditionals and INCLUDEs
+my($XSS_work_idx, $cpp_next_tmp) = (0, "XSubPPtmpAAAA");
+
sub TrimWhitespace
{
$_[0] =~ s/^\s+|\s+$//go ;
$type = TidyType($type) ;
$type_kind{$type} = $kind ;
# prototype defaults to '$'
- $proto = '$' unless $proto ;
+ $proto = "\$" unless $proto ;
warn("Warning: File '$typemap' Line $. '$line' Invalid prototype '$proto'\n")
unless ValidProtoString($proto) ;
$proto_letter{$type} = C_string($proto) ;
# check for duplicate alias name & duplicate value
Warn("Warning: Ignoring duplicate alias '$orig_alias'")
- if defined $XsubAliases{$pname}{$alias} ;
+ if defined $XsubAliases{$alias} ;
- Warn("Warning: Aliases '$orig_alias' and '$XsubAliasValues{$pname}{$value}' have identical values")
- if $XsubAliasValues{$pname}{$value} ;
+ Warn("Warning: Aliases '$orig_alias' and '$XsubAliasValues{$value}' have identical values")
+ if $XsubAliasValues{$value} ;
- $XsubAliases{$pname}{$alias} = $value ;
- $XsubAliasValues{$pname}{$value} = $orig_alias ;
+ $XsubAliases = 1;
+ $XsubAliases{$alias} = $value ;
+ $XsubAliasValues{$value} = $orig_alias ;
}
blurt("Error: Cannot parse ALIAS definitions from '$orig'")
sub PROTOTYPE_handler ()
{
+ my $specified ;
+
death("Error: Only 1 PROTOTYPE definition allowed per xsub")
if $proto_in_this_xsub ++ ;
for (; !/^$BLOCK_re/o; $_ = shift(@line)) {
next unless /\S/;
+ $specified = 1 ;
TrimWhitespace($_) ;
if ($_ eq 'DISABLE') {
$ProtoThisXSUB = 0
}
}
+ # If no prototype specified, then assume empty prototype ""
+ $ProtoThisXSUB = 2 unless $specified ;
+
$ProtoUsed = 1 ;
}
++ $IncludedFiles{$_} unless /\|\s*$/ ;
# Save the current file context.
- push(@FileStack, {
+ push(@XSStack, {
+ type => 'file',
LastLine => $lastline,
LastLineNo => $lastline_no,
Line => \@line,
sub PopFile()
{
- return 0 unless @FileStack ;
-
- my $data = pop @FileStack ;
+ return 0 unless $XSStack[-1]{type} eq 'file' ;
+
+ my $data = pop @XSStack ;
my $ThisFile = $filename ;
my $isPipe = ($filename =~ /\|\s*$/) ;
$lastline_no = $data->{LastLineNo} ;
@line = @{ $data->{Line} } ;
@line_no = @{ $data->{LineNo} } ;
-
+
if ($isPipe and $? ) {
-- $lastline_no ;
print STDERR "Error reading from pipe '$ThisFile': $! in $filename, line $lastline_no\n" ;
{
my ($type) = @_ ;
- $proto_letter{$type} or '$' ;
+ $proto_letter{$type} or "\$" ;
}
sub check_cpp {
$cpplevel++;
} elsif (!$cpplevel) {
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 $XSStack[-1]{type} eq 'if';
return;
} elsif ($cpp =~ /^\#\s*endif/) {
$cpplevel--;
print <<EOM ;
/*
* This file was generated automatically by xsubpp version $XSUBPP_version from the
- * contents of $filename. Don't edit this file, edit $filename instead.
+ * contents of $filename. Do not edit this file, edit $filename instead.
*
* ANY CHANGES MADE HERE WILL BE LOST!
*
# Read next xsub into @line from ($lastline, <$FH>).
sub fetch_para {
# parse paragraph
+ death ("Error: Unterminated `#if/#ifdef/#ifndef'")
+ if !defined $lastline && $XSStack[-1]{type} eq 'if';
@line = ();
@line_no = () ;
- if (! defined $lastline) {
- return 1 if PopFile() ;
- return 0 ;
- }
+ return PopFile() if !defined $lastline;
if ($lastline =~
/^MODULE\s*=\s*([\w:]+)(?:\s+PACKAGE\s*=\s*([\w:]+))?(?:\s+PREFIX\s*=\s*(\S+))?\s*$/) {
for(;;) {
if ($lastline !~ /^\s*#/ ||
- $lastline =~ /^#[ \t]*(?:(?:if|ifn?def|else|elif|endif|define|undef|pragma)\b|include\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)
+ $lastline =~ /^#[ \t]*(?:(?:if|ifn?def|elif|else|endif|define|undef|pragma|error|warning|line\s+\d+|ident)\b|(?:include(?:_next)?|import)\s*["<].*[>"])/) {
last if $lastline =~ /^\S/ && @line && $line[-1] eq "";
push(@line, $lastline);
push(@line_no, $lastline_no) ;
PARAGRAPH:
while (fetch_para()) {
# Print initial preprocessor statements and blank lines
- print shift(@line), "\n"
- while @line && $line[0] !~ /^[^\#]/;
+ while (@line && $line[0] !~ /^[^\#]/) {
+ my $line = shift(@line);
+ print $line, "\n";
+ next unless $line =~ /^\#\s*((if)(?:n?def)?|elsif|else|endif)\b/;
+ my $statement = $+;
+ if ($statement eq 'if') {
+ $XSS_work_idx = @XSStack;
+ push(@XSStack, {type => 'if'});
+ } else {
+ death ("Error: `$statement' with no matching `if'")
+ if $XSStack[-1]{type} ne 'if';
+ if ($XSStack[-1]{varname}) {
+ push(@InitFileCode, "#endif\n");
+ push(@BootCode, "#endif");
+ }
+
+ my(@fns) = keys %{$XSStack[-1]{functions}};
+ if ($statement ne 'endif') {
+ # Hide the functions defined in other #if branches, and reset.
+ @{$XSStack[-1]{other_functions}}{@fns} = (1) x @fns;
+ @{$XSStack[-1]}{qw(varname functions)} = ('', {});
+ } else {
+ my($tmp) = pop(@XSStack);
+ 0 while (--$XSS_work_idx
+ && $XSStack[$XSS_work_idx]{type} ne 'if');
+ # Keep all new defined functions
+ push(@fns, keys %{$tmp->{other_functions}});
+ @{$XSStack[$XSS_work_idx]{functions}}{@fns} = (1) x @fns;
+ }
+ }
+ }
next PARAGRAPH unless @line;
+ if ($XSS_work_idx && !$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(@InitFileCode, "#if $cpp_next_tmp\n");
+ push(@BootCode, "#if $cpp_next_tmp");
+ $XSStack[$XSS_work_idx]{varname} = $cpp_next_tmp++;
+ }
+
death ("Code is not inside a function")
if $line[0] =~ /^\s/;
($class, $func_name, $orig_args) = ($1, $2, $3) ;
($pname = $func_name) =~ s/^($Prefix)?/$Packprefix/;
+ $Full_func_name = "${Packid}_$func_name";
# Check for duplicate function definition
- if (defined $Func_name{"${Packid}_$func_name"} ) {
- Warn("Warning: duplicate function definition '$func_name' detected")
- }
- else {
- push(@Func_name, "${Packid}_$func_name");
- push(@Func_pname, $pname);
+ for $tmp (@XSStack) {
+ next unless defined $tmp->{functions}{$Full_func_name};
+ Warn("Warning: duplicate function definition '$func_name' detected");
+ last;
}
- $Func_name{"${Packid}_$func_name"} ++ ;
+ $XSStack[$XSS_work_idx]{functions}{$Full_func_name} ++ ;
+ %XsubAliases = %XsubAliasValues = ();
@args = split(/\s*,\s*/, $orig_args);
if (defined($class)) {
$defaults{$args[$i]} = $2;
$defaults{$args[$i]} =~ s/"/\\"/g;
}
- $proto_arg[$i+1] = '$' ;
+ $proto_arg[$i+1] = "\$" ;
}
if (defined($class)) {
$func_args = join(", ", @args[1..$#args]);
@args_match{@args} = 1..@args;
$PPCODE = grep(/^\s*PPCODE\s*:/, @line);
+ $CODE = grep(/^\s*CODE\s*:/, @line);
$ALIAS = grep(/^\s*ALIAS\s*:/, @line);
# print function header
# croak(errbuf);
EOF
- print Q<<EOF unless $PPCODE;
+ if ($ret_type ne "void" or $CODE) {
+ print Q<<EOF unless $PPCODE;
# XSRETURN(1);
EOF
+ } else {
+ print Q<<EOF unless $PPCODE;
+# XSRETURN_EMPTY;
+EOF
+ }
print Q<<EOF;
#]]
#
EOF
+ my $newXS = "newXS" ;
+ my $proto = "" ;
+
# Build the prototype string for the xsub
if ($ProtoThisXSUB) {
- if ($ProtoThisXSUB != 1) {
- $ProtoXSUB{$pname} = '"' . $ProtoThisXSUB . '"'
+ $newXS = "newXSproto";
+
+ if ($ProtoThisXSUB == 2) {
+ # User has specified empty prototype
+ $proto = ', ""' ;
+ }
+ elsif ($ProtoThisXSUB != 1) {
+ # User has specified a prototype
+ $proto = ', "' . $ProtoThisXSUB . '"';
}
else {
my $s = ';';
$s = '';
$proto_arg[$min_args] .= ";" ;
}
- push @proto_arg, "${s}@"
+ push @proto_arg, "$s\@"
if $elipsis ;
- $ProtoXSUB{$pname} = '"' . join ("", @proto_arg) . '"'
+ $proto = ', "' . join ("", @proto_arg) . '"';
}
}
+ if (%XsubAliases) {
+ $XsubAliases{$pname} = 0
+ unless defined $XsubAliases{$pname} ;
+ while ( ($name, $value) = each %XsubAliases) {
+ push(@InitFileCode, Q<<"EOF");
+# cv = newXS(\"$name\", XS_$Full_func_name, file);
+# XSANY.any_i32 = $value ;
+EOF
+ push(@InitFileCode, Q<<"EOF") if $proto;
+# sv_setpv((SV*)cv$proto) ;
+EOF
+ }
+ }
+ else {
+ push(@InitFileCode,
+ " ${newXS}(\"$pname\", XS_$Full_func_name, file$proto);\n");
+ }
}
# print initialization routine
#
EOF
-print Q<<"EOF" if defined %XsubAliases ;
+print Q<<"EOF" if defined $XsubAliases ;
# {
# CV * cv ;
#
EOF
-for (@Func_name) {
- $pname = shift(@Func_pname);
- my $newXS = "newXS" ;
- my $proto = "" ;
+print @InitFileCode;
- if ($ProtoXSUB{$pname}) {
- $newXS = "newXSproto" ;
- $proto = ", $ProtoXSUB{$pname}" ;
- }
-
- if ($XsubAliases{$pname}) {
- $XsubAliases{$pname}{$pname} = 0
- unless defined $XsubAliases{$pname}{$pname} ;
- while ( ($name, $value) = each %{$XsubAliases{$pname}}) {
- print Q<<"EOF" ;
-# cv = newXS(\"$name\", XS_$_, file);
-# XSANY.any_i32 = $value ;
-EOF
- print Q<<"EOF" if $proto ;
-# sv_setpv((SV*)cv, $ProtoXSUB{$pname}) ;
-EOF
- }
- }
- else {
- print " ${newXS}(\"$pname\", XS_$_, file$proto);\n";
- }
-}
-
-print Q<<"EOF" if defined %XsubAliases ;
+print Q<<"EOF" if defined $XsubAliases ;
# }
EOF
$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/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/;
}
eval "print qq\a$expr\a";
}
elsif ($var eq 'RETVAL') {
- if ($expr =~ /^\t\$arg = /) {
+ if ($expr =~ /^\t\$arg\s*=\s*\$var\s*;/) {
+ eval "print qq\a$expr\a";
+ print "\tif (SvREFCNT(ST(0))) sv_2mortal(ST(0));\n";
+ }
+ elsif ($expr =~ /^\t\$arg = /) {
eval "print qq\a$expr\a";
print "\tsv_2mortal(ST(0));\n";
}