4 $usage = "Usage: xsubpp [-ansi] [-C++] [-except] [-tm typemap] file.xs\n";
6 SWITCH: while ($ARGV[0] =~ s/^-//) {
8 $ansiflag = 1, next SWITCH if $flag eq 'ansi';
9 $spat = shift, next SWITCH if $flag eq 's';
10 $cplusplus = 1, next SWITCH if $flag eq 'C++';
11 $except = 1, next SWITCH if $flag eq 'except';
12 push(@tm,shift), next SWITCH if $flag eq 'typemap';
15 @ARGV == 1 or die $usage;
17 ($dir, $filename) = @ARGV[0] =~ m#(.*)/(.*)#
18 or ($dir, $filename) = ('.', $ARGV[0]);
21 $typemap = shift @ARGV;
22 foreach $typemap (@tm) {
23 die "Can't find $typemap in $pwd\n" unless -r $typemap;
25 unshift @tm, qw(../../../typemap ../../typemap ../typemap typemap);
26 foreach $typemap (@tm) {
27 open(TYPEMAP, $typemap) || next;
32 if (/^INPUT\s*$/) { $mode = Input, next }
33 if (/^OUTPUT\s*$/) { $mode = Output, next }
34 if (/^TYPEMAP\s*$/) { $mode = Typemap, next }
35 if ($mode eq Typemap) {
37 ($typename, $kind) = split(/\t+/, $_, 2);
38 $type_kind{$typename} = $kind if $kind ne '';
40 elsif ($mode eq Input) {
46 # $input_expr{$_} = '';
47 $current = \$input_expr{$_};
56 # $output_expr{$_} = '';
57 $current = \$output_expr{$_};
64 foreach $key (keys %input_expr) {
65 $input_expr{$key} =~ s/\n+$//;
76 open(F, $filename) || die "cannot open $filename\n";
79 last if ($Module, $foo, $Package, $foo1, $Prefix) =
80 /^MODULE\s*=\s*(\w+)(\s+PACKAGE\s*=\s*([\w:]+))?(\s+PREFIX\s*=\s*(\S+))?$/;
89 if ($lastline ne "") {
91 /^MODULE\s*=\s*(\w+)(\s+PACKAGE\s*=\s*([\w:]+))?(\s+PREFIX\s*=\s*(\S+))?$/) {
97 ($Packid = $Package) =~ s/:/_/g;
98 $Packprefix = $Package;
99 $Packprefix .= "::" if defined $Packprefix && $Packprefix ne "";
104 push(@line, $_) if $_ ne "";
107 push(@line, $lastline);
111 next if /^#/ && !/^#(if|ifdef|else|elif|endif|define|undef)\b/;
113 if (/^\S/ && @line && $line[-1] eq "") {
121 pop(@line) while @line && $line[-1] eq "";
126 while (&fetch_para) {
127 # initialize info arrays
136 # extract return type, function name and arguments
137 $ret_type = shift(@line);
138 if ($ret_type =~ /^static\s+(.*)$/) {
142 $func_header = shift(@line);
143 ($func_name, $orig_args) = $func_header =~ /^([\w:]+)\s*\((.*)\)$/;
144 if ($func_name =~ /(.*)::(.*)/) {
148 ($pname = $func_name) =~ s/^($Prefix)?/$Packprefix/;
149 push(@Func_name, "${Packid}_$func_name");
150 push(@Func_pname, $pname);
151 @args = split(/\s*,\s*/, $orig_args);
152 if (defined($class) && !defined($static)) {
153 unshift(@args, "THIS");
154 $orig_args = "THIS, $orig_args";
155 $orig_args =~ s/^THIS, $/THIS/;
157 $orig_args =~ s/"/\\"/g;
158 $min_args = $num_args = @args;
159 foreach $i (0..$num_args-1) {
160 if ($args[$i] =~ s/\.\.\.//) {
163 if ($args[i] eq '' && $i == $num_args - 1) {
168 if ($args[$i] =~ /([^=]*\S)\s*=\s*(.*)/) {
171 $defaults{$args[$i]} = $2;
172 $defaults{$args[$i]} =~ s/"/\\"/g;
175 if (defined($class) && !defined($static)) {
176 $func_args = join(", ", @args[1..$#args]);
178 $func_args = join(", ", @args);
180 @args_match{@args} = 1..@args;
182 # print function header
186 #XS_${Packid}_$func_name(int, int ax, int items)
193 #XS_${Packid}_$func_name(ix, ax, items)
201 $cond = qq(items < $min_args);
203 elsif ($min_args == $num_args) {
204 $cond = qq(items != $min_args);
207 $cond = qq(items < $min_args || items > $num_args);
210 print Q<<"EOF" if $except;
217 # croak("Usage: $pname($orig_args)");
221 # Now do a block of some sort.
228 if ($_[0] =~ s/^\s*CASE\s*:\s*//) {
229 $cond = shift(@line);
231 print " if ($cond)\n";
233 elsif ($cond ne '') {
234 print " else if ($cond)\n";
253 # do initialization of input variables
259 last if /^\s*NOT_IMPLEMENTED_YET/;
260 last if /^\s*(PPCODE|CODE|OUTPUT|CLEANUP|CASE)\s*:/;
261 ($var_type, $var_name, $var_init) =
262 /\s*([^\t]+)\s*([^\s=]+)\s*(=.*)?/;
263 if ($var_name =~ /^&/) {
265 $var_addr{$var_name} = 1;
267 $thisdone |= $var_name eq "THIS";
268 $retvaldone |= $var_name eq "RETVAL";
269 $var_types{$var_name} = $var_type;
270 print "\t" . &map_type($var_type);
271 $var_num = $args_match{$var_name};
272 if ($var_addr{$var_name}) {
273 $func_args =~ s/\b($var_name)\b/&\1/;
275 if ($var_init !~ /^=\s*NO_INIT\s*$/) {
276 if ($var_init !~ /^\s*$/) {
277 &output_init($var_type, $var_num,
278 "$var_name $var_init");
280 # generate initialization code
281 &generate_init($var_type, $var_num, $var_name);
286 print "\t$var_name;\n";
289 if (!$thisdone && defined($class) && !defined($static)) {
291 $var_types{"THIS"} = "$class *";
292 &generate_init("$class *", 1, "THIS");
296 if (/^\s*NOT_IMPLEMENTED_YET/) {
297 print "\ncroak(\"$pname: not implemented yet\");\n";
299 if ($ret_type ne "void") {
300 print "\t" . &map_type($ret_type) . "\tRETVAL;\n"
302 $args_match{"RETVAL"} = 0;
303 $var_types{"RETVAL"} = $ret_type;
310 last if /^\s*(OUTPUT|CLEANUP|CASE)\s*:/;
313 print "\tax = sp - stack_base;\n";
314 } elsif (/^\s*CODE:/) {
318 last if /^\s*(OUTPUT|CLEANUP|CASE)\s*:/;
324 if ($ret_type ne "void") {
327 if (defined($static)) {
329 } elsif (defined($class)) {
332 if (defined($spat) && $func_name =~ /^($spat)(.*)$/) {
335 print "$func_name($func_args);\n";
336 &generate_output($ret_type, 0, "RETVAL")
337 unless $ret_type eq "void";
341 # do output variables
342 if (/^\s*OUTPUT\s*:/) {
345 last if /^\s*CLEANUP\s*:/;
347 ($outarg, $outcode) = split(/\t+/);
349 print "\t$outcode\n";
351 die "$outarg not an argument"
352 unless defined($args_match{$outarg});
353 $var_num = $args_match{$outarg};
354 &generate_output($var_types{$outarg}, $var_num,
360 if (/^\s*CLEANUP\s*:/) {
363 last if /^\s*CASE\s*:/;
367 # print function trailer
373 # sprintf(errbuf, "%s: %s\\tpropagated", Xname, Xreason);
382 if (/^\s*CASE\s*:/) {
386 print Q<<EOF if $except;
397 # print initialization routine
398 print qq/extern "C"\n/ if $cplusplus;
400 #int boot_$Module(ix,ax,items)
405 # char* file = __FILE__;
410 $pname = shift(@Func_pname);
411 print " newXSUB(\"$pname\", 0, XS_$_, file);\n";
416 local($type, $num, $init) = @_;
417 local($arg) = "ST($num)";
419 eval qq/print " $init\\\n"/;
422 sub blurt { warn @_; $errors++ }
425 local($type, $num, $var) = @_;
426 local($arg) = "ST($num)";
427 local($argoff) = $num - 1;
431 blurt("$type not in typemap"), return unless defined($type_kind{$type});
432 ($ntype = $type) =~ s/\s*\*/Ptr/g;
434 $subtype =~ s/Ptr$//;
435 $subtype =~ s/Array$//;
436 $tk = $type_kind{$type};
437 $tk =~ s/OBJ$/REF/ if $func_name =~ /DESTROY$/;
439 $expr = $input_expr{$tk};
440 if ($expr =~ /DO_ARRAY_ELEM/) {
441 $subexpr = $input_expr{$type_kind{$subtype}};
442 $subexpr =~ s/ntype/subtype/g;
443 $subexpr =~ s/\$arg/ST(ix_$var)/g;
444 $subexpr =~ s/\n\t/\n\t\t/g;
445 $subexpr =~ s/is not of (.*")/[arg %d] is not of $1, ix_$var + 1/g;
446 $subexpr =~ s/\$var/$var[ix_$var - $argoff]/;
447 $expr =~ s/DO_ARRAY_ELEM/$subexpr/;
449 if (defined($defaults{$var})) {
450 $expr =~ s/(\t+)/$1 /g;
452 eval qq/print "\\t$var;\\n"/;
453 $deferred .= eval qq/"\\n\\tif (items < $num)\\n\\t $var = $defaults{$var};\\n\\telse {\\n$expr;\\n\\t}\\n"/;
454 } elsif ($expr !~ /^\t\$var =/) {
455 eval qq/print "\\t$var;\\n"/;
456 $deferred .= eval qq/"\\n$expr;\\n"/;
458 eval qq/print "$expr;\\n"/;
462 sub generate_output {
463 local($type, $num, $var) = @_;
464 local($arg) = "ST($num)";
465 local($argoff) = $num - 1;
468 if ($type =~ /^array\(([^,]*),(.*)\)/) {
469 print "\tsv_setpvn($arg, (char *)$var, $2 * sizeof($1)), XFree((char *)$var);\n";
471 blurt("$type not in typemap"), return
472 unless defined($type_kind{$type});
473 ($ntype = $type) =~ s/\s*\*/Ptr/g;
476 $subtype =~ s/Ptr$//;
477 $subtype =~ s/Array$//;
478 $expr = $output_expr{$type_kind{$type}};
479 if ($expr =~ /DO_ARRAY_ELEM/) {
480 $subexpr = $output_expr{$type_kind{$subtype}};
481 $subexpr =~ s/ntype/subtype/g;
482 $subexpr =~ s/\$arg/ST(ix_$var)/g;
483 $subexpr =~ s/\$var/${var}[ix_$var]/g;
484 $subexpr =~ s/\n\t/\n\t\t/g;
485 $expr =~ s/DO_ARRAY_ELEM\n/$subexpr/;
486 eval "print qq\f$expr\f";
488 elsif ($arg eq 'ST(0)') {
489 if ($expr =~ /^\t\$arg = /) {
490 eval "print qq\f$expr\f";
491 print "\tsv_2mortal(ST(0));\n";
494 print "\tST(0) = sv_newmortal();\n";
495 eval "print qq\f$expr\f";
505 if ($type =~ /^array\(([^,]*),(.*)\)/) {