This may significantly slow down the generated code, but this is the way
B<xsubpp> of 5.005 and earlier operated.
+=item B<-noinout>
+
+Disable recognition of C<IN>, C<OUT_LIST> and C<INOUT_LIST> declarations.
+
+=item B<-noargtypes>
+
+Disable recognition of ANSI-like descriptions of function signature.
+
=back
=head1 ENVIRONMENT
$FH = 'File0000' ;
-$usage = "Usage: xsubpp [-v] [-C++] [-except] [-prototypes] [-noversioncheck] [-nolinenumbers] [-nooptimize] [-s pattern] [-typemap typemap]... file.xs\n";
+$usage = "Usage: xsubpp [-v] [-C++] [-except] [-prototypes] [-noversioncheck] [-nolinenumbers] [-nooptimize] [-noinout] [-noargtypes] [-s pattern] [-typemap typemap]... file.xs\n";
$proto_re = "[" . quotemeta('\$%&*@;') . "]" ;
# mjn
$ProtoUsed = 0 ;
$WantLineNumbers = 1 ;
$WantOptimize = 1 ;
+
+my $process_inout = 1;
+my $process_argtypes = 1;
+
SWITCH: while (@ARGV and $ARGV[0] =~ /^-./) {
$flag = shift @ARGV;
$flag =~ s/^-// ;
$WantLineNumbers = 1, next SWITCH if $flag eq 'linenumbers';
$WantOptimize = 0, next SWITCH if $flag eq 'nooptimize';
$WantOptimize = 1, next SWITCH if $flag eq 'optimize';
+ $process_inout = 0, next SWITCH if $flag eq 'noinout';
+ $process_inout = 1, next SWITCH if $flag eq 'inout';
+ $process_argtypes = 0, next SWITCH if $flag eq 'noargtypes';
+ $process_argtypes = 1, next SWITCH if $flag eq 'argtypes';
(print "xsubpp version $XSUBPP_version\n"), exit
if $flag eq 'v';
die $usage;
$input_expr{$key} =~ s/\n+$//;
}
-$bal = qr[(?:(?>[^()]+)|\((?p{ $bal })\))*]; # ()-balanced
+$bal = qr[(?:(?>[^()]+)|\((??{ $bal })\))*]; # ()-balanced
$cast = qr[(?:\(\s*SV\s*\*\s*\)\s*)?]; # Optional (SV*) cast
-$size = qr[,\s* (?p{ $bal }) ]x; # Third arg (to setpvn)
+$size = qr[,\s* (??{ $bal }) ]x; # Third arg (to setpvn)
foreach $key (keys %output_expr) {
use re 'eval';
($output_expr{$key} =~
m[^ \s+ sv_set ( [iunp] ) v (n)? # Type, is_setpvn
\s* \( \s* $cast \$arg \s* ,
- \s* ( (?p{ $bal }) ) # Set from
- ( (?p{ $size }) )? # Possible sizeof set-from
+ \s* ( (??{ $bal }) ) # Set from
+ ( (??{ $size }) )? # Possible sizeof set-from
\) \s* ; \s* $
]x);
$targetable{$key} = [$t, $with_size, $arg, $sarg] if $t;
# Match an XS keyword
$BLOCK_re= '\s*(' . join('|', qw(
REQUIRE BOOT CASE PREINIT INPUT INIT CODE PPCODE OUTPUT
- CLEANUP ALIAS PROTOTYPES PROTOTYPE VERSIONCHECK INCLUDE
- SCOPE INTERFACE INTERFACE_MACRO C_ARGS POST_CALL
+ CLEANUP ALIAS ATTRS PROTOTYPES PROTOTYPE VERSIONCHECK INCLUDE
+ SCOPE INTERFACE INTERFACE_MACRO C_ARGS POSTCALL
)) . "|$END)\\s*:";
# Input: ($_, @line) == unparsed input.
my ($C_group_rex, $C_arg);
# Group in C (no support for comments or literals)
$C_group_rex = qr/ [({\[]
- (?: (?> [^()\[\]{}]+ ) | (?p{ $C_group_rex }) )*
+ (?: (?> [^()\[\]{}]+ ) | (??{ $C_group_rex }) )*
[)}\]] /x ;
# Chunk in C without comma at toplevel (no comments):
$C_arg = qr/ (?: (?> [^()\[\]{},"']+ )
- | (?p{ $C_group_rex })
+ | (??{ $C_group_rex })
| " (?: (?> [^\\"]+ )
| \\.
)* " # String literal
$_ = '' ;
}
-my $process_inout = 1;
-my $process_argtypes = 1;
-
sub INPUT_handler {
for (; !/^$BLOCK_re/o; $_ = shift(@line)) {
last if /^\s*NOT_IMPLEMENTED_YET/;
$func_args =~ s/\b($var_name)\b/&$1/;
}
if ($var_init =~ /^[=;]\s*NO_INIT\s*;?\s*$/
- or $in_out{$var_name} and $in_out{$var_name} eq 'outlist'
+ or $in_out{$var_name} and $in_out{$var_name} eq 'OUTLIST'
and $var_init !~ /\S/) {
if ($name_printed) {
print ";\n";
sub CLEANUP_handler() { print_section() }
sub PREINIT_handler() { print_section() }
-sub POST_CALL_handler() { print_section() }
+sub POSTCALL_handler() { print_section() }
sub INIT_handler() { print_section() }
sub GetAliases
if $line ;
}
+sub ATTRS_handler ()
+{
+ for (; !/^$BLOCK_re/o; $_ = shift(@line)) {
+ next unless /\S/;
+ TrimWhitespace($_) ;
+ push @Attributes, $_;
+ }
+}
+
sub ALIAS_handler ()
{
for (; !/^$BLOCK_re/o; $_ = shift(@line)) {
print("#line 1 \"$filename\"\n")
if $WantLineNumbers;
+firstmodule:
while (<$FH>) {
+ if (/^=/) {
+ do {
+ next firstmodule if /^=cut\s*$/;
+ } while (<$FH>);
+ &Exit;
+ }
last if ($Module, $Package, $Prefix) =
/^MODULE\s*=\s*([\w:]+)(?:\s+PACKAGE\s*=\s*([\w:]+))?(?:\s+PREFIX\s*=\s*(\S+))?\s*$/;
}
for(;;) {
+ # Skip embedded PODs
+ while ($lastline =~ /^=/) {
+ while ($lastline = <$FH>) {
+ last if ($lastline =~ /^=cut\s*$/);
+ }
+ death ("Error: Unterminated pod") unless $lastline;
+ $lastline = <$FH>;
+ chomp $lastline;
+ $lastline =~ s/^\s+$//;
+ }
if ($lastline !~ /^\s*#/ ||
# CPP directives:
# ANSI: if ifdef ifndef elif else endif define undef
($ret_type) = TidyType($_);
$RETVAL_no_return = 1 if $ret_type =~ s/^NO_OUTPUT\s+//;
+ # Allow one-line ANSI-like declaration
+ unshift @line, $2
+ if $process_argtypes
+ and $ret_type =~ s/^(.*?\w.*?)\s*\b(\w+\s*\(.*)/$1/s;
+
# a function definition needs at least 2 lines
blurt ("Error: Function definition too short '$ret_type'"), next PARAGRAPH
unless @line ;
last;
}
$XSStack[$XSS_work_idx]{functions}{$Full_func_name} ++ ;
- %XsubAliases = %XsubAliasValues = %Interfaces = ();
+ %XsubAliases = %XsubAliasValues = %Interfaces = @Attributes = ();
$DoSetMagic = 1;
$orig_args =~ s/\\\s*/ /g; # process line continuations
my %out_vars;
if ($process_argtypes and $orig_args =~ /\S/) {
my $args = "$orig_args ,";
- if ($args =~ /^( (?p{ $C_arg }) , )* $ /x) {
- @args = ($args =~ /\G ( (?p{ $C_arg }) ) , /xg);
+ if ($args =~ /^( (??{ $C_arg }) , )* $ /x) {
+ @args = ($args =~ /\G ( (??{ $C_arg }) ) , /xg);
for ( @args ) {
s/^\s+//;
s/\s+$//;
next unless length $pre;
my $out_type;
my $inout_var;
- if ($process_inout and s/^(in|in_outlist|outlist)\s+//) {
+ if ($process_inout and s/^(IN|IN_OUTLIST|OUTLIST)\s+//) {
my $type = $1;
- $out_type = $type if $type ne 'in';
- $arg =~ s/^(in|in_outlist|outlist)\s+//;
+ $out_type = $type if $type ne 'IN';
+ $arg =~ s/^(IN|IN_OUTLIST|OUTLIST)\s+//;
}
if (/\W/) { # Has a type
push @arg_with_types, $arg;
$arg_types{$name} = $arg;
$_ = "$name$default";
}
- $out_vars{$_} = 1 if $out_type eq 'outlist';
+ $out_vars{$_} = 1 if $out_type eq 'OUTLIST';
push @in_out, $name if $out_type;
$in_out{$name} = $out_type if $out_type;
}
} else {
@args = split(/\s*,\s*/, $orig_args);
for (@args) {
- if ($process_inout and s/^(in|in_outlist|outlist)\s+//) {
+ if ($process_inout and s/^(IN|IN_OUTLIST|OUTLIST)\s+//) {
my $out_type = $1;
- next if $out_type eq 'in';
- $out_vars{$_} = 1 if $out_type eq 'outlist';
+ next if $out_type eq 'IN';
+ $out_vars{$_} = 1 if $out_type eq 'OUTLIST';
push @in_out, $name;
$in_out{$_} = $out_type;
}
$gotRETVAL = 0;
INPUT_handler() ;
- process_keyword("INPUT|PREINIT|INTERFACE_MACRO|C_ARGS|ALIAS|PROTOTYPE|SCOPE") ;
+ process_keyword("INPUT|PREINIT|INTERFACE_MACRO|C_ARGS|ALIAS|ATTRS|PROTOTYPE|SCOPE") ;
print Q<<"EOF" if $ScopeThisXSUB;
# ENTER;
}
print $deferred;
- process_keyword("INIT|ALIAS|PROTOTYPE|INTERFACE_MACRO|INTERFACE|C_ARGS") ;
+ process_keyword("INIT|ALIAS|ATTRS|PROTOTYPE|INTERFACE_MACRO|INTERFACE|C_ARGS") ;
if (check_keyword("PPCODE")) {
print_section();
# $wantRETVAL set if 'RETVAL =' autogenerated
($wantRETVAL, $ret_type) = (0, 'void') if $RETVAL_no_return;
undef %outargs ;
- process_keyword("POST_CALL|OUTPUT|ALIAS|PROTOTYPE");
+ process_keyword("POSTCALL|OUTPUT|ALIAS|ATTRS|PROTOTYPE");
# all OUTPUT done, so now push the return value on the stack
if ($gotRETVAL && $RETVAL_code) {
generate_output($var_types{$_}, $num++, $_, 0, 1) for @in_out;
# do cleanup
- process_keyword("CLEANUP|ALIAS|PROTOTYPE") ;
+ process_keyword("CLEANUP|ALIAS|ATTRS|PROTOTYPE") ;
print Q<<"EOF" if $ScopeThisXSUB;
# ]]
EOF
}
}
+ elsif (@Attributes) {
+ push(@InitFileCode, Q<<"EOF");
+# cv = newXS(\"$pname\", XS_$Full_func_name, file);
+# apply_attrs_string("$Package", cv, "@Attributes", 0);
+EOF
+ }
elsif ($interface) {
while ( ($name, $value) = each %Interfaces) {
$name = "$Package\::$name" unless $name =~ /::/;
$tk = $type_kind{$type};
$tk =~ s/OBJ$/REF/ if $func_name =~ /DESTROY$/;
$type =~ tr/:/_/;
- blurt("Error: No INPUT definition for type '$type' found"), return
+ blurt("Error: No INPUT definition for type '$type', typekind '$type_kind{$type}' found"), return
unless defined $input_expr{$tk} ;
$expr = $input_expr{$tk};
if ($expr =~ /DO_ARRAY_ELEM/) {
blurt("Error: '$subtype' not in typemap"), return
unless defined($type_kind{$subtype});
- blurt("Error: No INPUT definition for type '$subtype' found"), return
+ blurt("Error: No INPUT definition for type '$subtype', typekind '$type_kind{$subtype}' found"), return
unless defined $input_expr{$type_kind{$subtype}} ;
$subexpr = $input_expr{$type_kind{$subtype}};
$subexpr =~ s/ntype/subtype/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"/;
+ if ($defaults{$var} eq 'NO_INIT') {
+ $deferred .= eval qq/"\\n\\tif (items >= $num) {\\n$expr;\\n\\t}\\n"/;
+ } else {
+ $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 =/) {
if ($name_printed) {
} else {
blurt("Error: '$type' not in typemap"), return
unless defined($type_kind{$type});
- blurt("Error: No OUTPUT definition for type '$type' found"), return
+ blurt("Error: No OUTPUT definition for type '$type', typekind '$type_kind{$type}' found"), return
unless defined $output_expr{$type_kind{$type}} ;
($ntype = $type) =~ s/\s*\*/Ptr/g;
$ntype =~ s/\(\)//g;
if ($expr =~ /DO_ARRAY_ELEM/) {
blurt("Error: '$subtype' not in typemap"), return
unless defined($type_kind{$subtype});
- blurt("Error: No OUTPUT definition for type '$subtype' found"), return
+ blurt("Error: No OUTPUT definition for type '$subtype', typekind '$type_kind{$subtype}' found"), return
unless defined $output_expr{$type_kind{$subtype}} ;
$subexpr = $output_expr{$type_kind{$subtype}};
$subexpr =~ s/ntype/subtype/g;