X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FExtUtils%2Fxsubpp;h=1ee7b29449e124ab8e44405e4c701afc503cc373;hb=4619340914cc8b5438e9411eca00b9f6a4805995;hp=8e253ff215efed3936414170b2bb1be7fbb8b8b1;hpb=b207eff1ea454206afe170b4d927f265fef3e83a;p=p5sagit%2Fp5-mst-13.2.git diff --git a/lib/ExtUtils/xsubpp b/lib/ExtUtils/xsubpp index 8e253ff..1ee7b29 100755 --- a/lib/ExtUtils/xsubpp +++ b/lib/ExtUtils/xsubpp @@ -86,6 +86,7 @@ perl(1), perlxs(1), perlxstut(1) require 5.002; use Cwd; use vars '$cplusplus'; +use vars '%v'; use Config; @@ -93,7 +94,7 @@ sub Q ; # Global Constants -$XSUBPP_version = "1.9506"; +$XSUBPP_version = "1.9507"; my ($Is_VMS, $SymSet); if ($^O eq 'VMS') { @@ -243,7 +244,7 @@ $END = "!End!\n\n"; # "impossible" keyword (multiple newline) $BLOCK_re= '\s*(' . join('|', qw( REQUIRE BOOT CASE PREINIT INPUT INIT CODE PPCODE OUTPUT CLEANUP ALIAS PROTOTYPES PROTOTYPE VERSIONCHECK INCLUDE - SCOPE + SCOPE INTERFACE INTERFACE_MACRO C_ARGS )) . "|$END)\\s*:"; # Input: ($_, @line) == unparsed input. @@ -310,6 +311,20 @@ sub print_section { print "$xsubpp::counter::SECTION_END_MARKER\n" if $WantLineNumbers; } +sub merge_section { + my $in = ''; + + while (!/\S/ && @line) { + $_ = shift(@line); + } + + for (; defined($_) && !/^$BLOCK_re/o; $_ = shift(@line)) { + $in .= "$_\n"; + } + chomp $in; + return $in; +} + sub process_keyword($) { my($pattern) = @_ ; @@ -337,11 +352,11 @@ sub INPUT_handler { my $line = $_ ; # remove trailing semicolon if no initialisation - s/\s*;$//g unless /=/ ; + s/\s*;$//g unless /[=;+].*\S/ ; # check for optional initialisation code my $var_init = '' ; - $var_init = $1 if s/\s*(=.*)$//s ; + $var_init = $1 if s/\s*([=;+].*)$//s ; $var_init =~ s/"/\\"/g; s/\s+/ /g; @@ -364,10 +379,10 @@ sub INPUT_handler { $var_addr{$var_name} = 1; $func_args =~ s/\b($var_name)\b/&$1/; } - if ($var_init =~ /^=\s*NO_INIT\s*;?\s*$/) { + if ($var_init =~ /^[=;]\s*NO_INIT\s*;?\s*$/) { print "\t$var_name;\n"; } elsif ($var_init =~ /\S/) { - &output_init($var_type, $var_num, "$var_name $var_init"); + &output_init($var_type, $var_num, $var_name, $var_init); } elsif ($var_num) { # generate initialization code &generate_init($var_type, $var_num, $var_name); @@ -407,6 +422,42 @@ sub OUTPUT_handler { } } +sub C_ARGS_handler() { + my $in = merge_section(); + + TrimWhitespace($in); + $func_args = $in; +} + +sub INTERFACE_MACRO_handler() { + my $in = merge_section(); + + TrimWhitespace($in); + if ($in =~ /\s/) { # two + ($interface_macro, $interface_macro_set) = split ' ', $in; + } else { + $interface_macro = $in; + $interface_macro_set = 'UNKNOWN_CVT'; # catch later + } + $interface = 1; # local + $Interfaces = 1; # global +} + +sub INTERFACE_handler() { + my $in = merge_section(); + + TrimWhitespace($in); + + foreach (split /[\s,]+/, $in) { + $Interfaces{$_} = $_; + } + print Q<<"EOF"; +# XSFUNCTION = $interface_macro($ret_type,cv,XSANY.any_dptr); +EOF + $interface = 1; # local + $Interfaces = 1; # global +} + sub CLEANUP_handler() { print_section() } sub PREINIT_handler() { print_section() } sub INIT_handler() { print_section() } @@ -725,12 +776,14 @@ while (<$FH>) { /^MODULE\s*=\s*([\w:]+)(?:\s+PACKAGE\s*=\s*([\w:]+))?(?:\s+PREFIX\s*=\s*(\S+))?\s*$/; if ($OBJ) { - s/#if(?:def|\s+defined)\s+(\(__cplusplus\)|__cplusplus)/#if defined(__cplusplus) && !defined(PERL_OBJECT)/; + s/#if(?:def\s|\s+defined)\s*(\(__cplusplus\)|__cplusplus)/#if defined(__cplusplus) && !defined(PERL_OBJECT)/; } print $_; } &Exit unless defined $_; +print "$xsubpp::counter::SECTION_END_MARKER\n" if $WantLineNumbers; + $lastline = $_; $lastline_no = $.; @@ -847,6 +900,9 @@ while (fetch_para()) { undef(@proto_arg) ; undef($proto_in_this_xsub) ; undef($scope_in_this_xsub) ; + undef($interface); + $interface_macro = 'XSINTERFACE_FUNC' ; + $interface_macro_set = 'XSINTERFACE_FUNC_SET' ; $ProtoThisXSUB = $WantPrototypes ; $ScopeThisXSUB = 0; @@ -867,7 +923,7 @@ while (fetch_para()) { # extract return type, function name and arguments - my($ret_type) = TidyType($_); + ($ret_type) = TidyType($_); # a function definition needs at least 2 lines blurt ("Error: Function definition too short '$ret_type'"), next PARAGRAPH @@ -877,9 +933,10 @@ while (fetch_para()) { $func_header = shift(@line); blurt ("Error: Cannot parse function definition from '$func_header'"), next PARAGRAPH - unless $func_header =~ /^(?:([\w:]*)::)?(\w+)\s*\(\s*(.*?)\s*\)\s*$/s; + unless $func_header =~ /^(?:([\w:]*)::)?(\w+)\s*\(\s*(.*?)\s*\)\s*(const)?\s*$/s; ($class, $func_name, $orig_args) = ($1, $2, $3) ; + $class = "$4 $class" if $4; ($pname = $func_name) =~ s/^($Prefix)?/$Packprefix/; ($clean_func_name = $func_name) =~ s/^$Prefix//; $Full_func_name = "${Packid}_$clean_func_name"; @@ -892,7 +949,7 @@ while (fetch_para()) { last; } $XSStack[$XSS_work_idx]{functions}{$Full_func_name} ++ ; - %XsubAliases = %XsubAliasValues = (); + %XsubAliases = %XsubAliasValues = %Interfaces = (); $DoSetMagic = 1; @args = split(/\s*,\s*/, $orig_args); @@ -935,6 +992,7 @@ while (fetch_para()) { $EXPLICIT_RETURN = ($CODE && ("@line" =~ /(\bST\s*\([^;]*=) | (\bXST_m\w+\s*\()/x )); $ALIAS = grep(/^\s*ALIAS\s*:/, @line); + $INTERFACE = grep(/^\s*INTERFACE\s*:/, @line); # print function header print Q<<"EOF"; @@ -945,6 +1003,9 @@ EOF print Q<<"EOF" if $ALIAS ; # dXSI32; EOF + print Q<<"EOF" if $INTERFACE ; +# dXSFUNCTION($ret_type); +EOF if ($elipsis) { $cond = ($min_args ? qq(items < $min_args) : 0); } @@ -997,7 +1058,7 @@ EOF $gotRETVAL = 0; INPUT_handler() ; - process_keyword("INPUT|PREINIT|ALIAS|PROTOTYPE|SCOPE") ; + process_keyword("INPUT|PREINIT|INTERFACE_MACRO|C_ARGS|ALIAS|PROTOTYPE|SCOPE") ; print Q<<"EOF" if $ScopeThisXSUB; # ENTER; @@ -1031,7 +1092,7 @@ EOF print $deferred; - process_keyword("INIT|ALIAS|PROTOTYPE") ; + process_keyword("INIT|ALIAS|PROTOTYPE|INTERFACE_MACRO|INTERFACE|C_ARGS") ; if (check_keyword("PPCODE")) { print_section(); @@ -1064,6 +1125,7 @@ EOF } $func_name =~ s/^($spat)// if defined($spat); + $func_name = 'XSFUNCTION' if $interface; print "$func_name($func_args);\n"; } } @@ -1172,6 +1234,18 @@ EOF # sv_setpv((SV*)cv$proto) ; EOF } + } + elsif ($interface) { + while ( ($name, $value) = each %Interfaces) { + $name = "$Package\::$name" unless $name =~ /::/; + push(@InitFileCode, Q<<"EOF"); +# cv = newXS(\"$name\", XS_$Full_func_name, file); +# $interface_macro_set(cv,$value) ; +EOF + push(@InitFileCode, Q<<"EOF") if $proto; +# sv_setpv((SV*)cv$proto) ; +EOF + } } else { push(@InitFileCode, @@ -1180,37 +1254,44 @@ EOF } # print initialization routine -if ($WantCAPI) { + print Q<<"EOF"; -# ##ifdef __cplusplus #extern "C" ##endif +EOF + +if ($WantCAPI) { +print Q<<"EOF"; +##ifdef PERL_CAPI #XS(boot__CAPI_entry) -#[[ -# dXSARGS; -# char* file = __FILE__; -# +##else EOF -} else { +} + print Q<<"EOF"; -##ifdef __cplusplus -#extern "C" -##endif #XS(boot_$Module_cname) +EOF + +if ($WantCAPI) { +print Q<<"EOF"; +##endif /* PERL_CAPI */ +EOF +} + +print Q<<"EOF"; #[[ # dXSARGS; # char* file = __FILE__; # EOF -} print Q<<"EOF" if $WantVersionChk ; # XS_VERSION_BOOTCHECK ; # EOF -print Q<<"EOF" if defined $XsubAliases ; +print Q<<"EOF" if defined $XsubAliases or defined $Interfaces ; # { # CV * cv ; # @@ -1218,7 +1299,7 @@ EOF print @InitFileCode; -print Q<<"EOF" if defined $XsubAliases ; +print Q<<"EOF" if defined $XsubAliases or defined $Interfaces ; # } EOF @@ -1231,15 +1312,14 @@ if (@BootCode) } print Q<<"EOF";; -# ST(0) = &sv_yes; -# XSRETURN(1); +# XSRETURN_YES; #]] # EOF if ($WantCAPI) { print Q<<"EOF"; -# +##ifdef PERL_CAPI ##define XSCAPI(name) void name(CV* cv, void* pPerl) # ##ifdef __cplusplus @@ -1250,7 +1330,7 @@ print Q<<"EOF"; # SetCPerlObj(pPerl); # boot__CAPI_entry(cv); #]] -# +##endif /* PERL_CAPI */ EOF } @@ -1258,12 +1338,24 @@ warn("Please specify prototyping behavior for $filename (see perlxs manual)\n") unless $ProtoUsed ; &Exit; - sub output_init { - local($type, $num, $init) = @_; + local($type, $num, $var, $init) = @_; local($arg) = "ST(" . ($num - 1) . ")"; - eval qq/print " $init\\\n"/; + if( $init =~ /^=/ ) { + eval qq/print "\\t$var $init\\n"/; + warn $@ if $@; + } else { + if( $init =~ s/^\+// && $num ) { + &generate_init($type, $num, $var); + } else { + eval qq/print "\\t$var;\\n"/; + warn $@ if $@; + $init =~ s/^;//; + } + $deferred .= eval qq/"\\n\\t$init\\n"/; + warn $@ if $@; + } } sub Warn @@ -1325,12 +1417,17 @@ sub generate_init { $expr =~ s/(\t+)/$1 /g; $expr =~ s/ /\t/g; eval qq/print "\\t$var;\\n"/; + warn $@ if $@; $deferred .= eval qq/"\\n\\tif (items < $num)\\n\\t $var = $defaults{$var};\\n\\telse {\\n$expr;\\n\\t}\\n"/; + warn $@ if $@; } elsif ($ScopeThisXSUB or $expr !~ /^\t\$var =/) { eval qq/print "\\t$var;\\n"/; + warn $@ if $@; $deferred .= eval qq/"\\n$expr;\\n"/; + warn $@ if $@; } else { eval qq/print "$expr;\\n"/; + warn $@ if $@; } } @@ -1365,6 +1462,7 @@ sub generate_output { $subexpr =~ s/\n\t/\n\t\t/g; $expr =~ s/DO_ARRAY_ELEM\n/$subexpr/; eval "print qq\a$expr\a"; + warn $@ if $@; print "\t\tSvSETMAGIC(ST(ix_$var));\n" if $do_setmagic; } elsif ($var eq 'RETVAL') { @@ -1372,18 +1470,16 @@ sub generate_output { # We expect that $arg has refcnt 1, so we need to # mortalize it. eval "print qq\a$expr\a"; + warn $@ if $@; print "\tsv_2mortal(ST(0));\n"; print "\tSvSETMAGIC(ST(0));\n" if $do_setmagic; } elsif ($expr =~ /^\s*\$arg\s*=/) { # We expect that $arg has refcnt >=1, so we need - # to mortalize it. However, the extension may have - # returned the built-in perl value, which is - # read-only, thus not mortalizable. However, it is - # safe to leave it as it is, since it would be - # ignored by REFCNT_dec. Builtin values have REFCNT==0. + # to mortalize it! eval "print qq\a$expr\a"; - print "\tif (SvREFCNT(ST(0))) sv_2mortal(ST(0));\n"; + warn $@ if $@; + print "\tsv_2mortal(ST(0));\n"; print "\tSvSETMAGIC(ST(0));\n" if $do_setmagic; } else { @@ -1393,11 +1489,13 @@ sub generate_output { # works too. print "\tST(0) = sv_newmortal();\n"; eval "print qq\a$expr\a"; + warn $@ if $@; # new mortals don't have set magic } } elsif ($arg =~ /^ST\(\d+\)$/) { eval "print qq\a$expr\a"; + warn $@ if $@; print "\tSvSETMAGIC($arg);\n" if $do_setmagic; } }