Re: Configure test for selectbits busted
[p5sagit/p5-mst-13.2.git] / lib / ExtUtils / xsubpp
CommitLineData
2304df62 1#!./miniperl
75f92628 2
3=head1 NAME
4
5xsubpp - compiler to convert Perl XS code into C code
6
7=head1 SYNOPSIS
8
b207eff1 9B<xsubpp> [B<-v>] [B<-C++>] [B<-except>] [B<-s pattern>] [B<-prototypes>] [B<-noversioncheck>] [B<-nolinenumbers>] [B<-typemap typemap>] [B<-object_capi>]... file.xs
75f92628 10
11=head1 DESCRIPTION
12
13I<xsubpp> will compile XS code into C code by embedding the constructs
14necessary to let C functions manipulate Perl values and creates the glue
15necessary to let Perl access those functions. The compiler uses typemaps to
16determine how to map C function parameters and variables to Perl values.
17
18The compiler will search for typemap files called I<typemap>. It will use
19the following search path to find default typemaps, with the rightmost
20typemap taking precedence.
21
22 ../../../typemap:../../typemap:../typemap:typemap
23
24=head1 OPTIONS
25
26=over 5
27
28=item B<-C++>
29
30Adds ``extern "C"'' to the C code.
31
32
33=item B<-except>
34
35Adds exception handling stubs to the C code.
36
37=item B<-typemap typemap>
38
39Indicates that a user-supplied typemap should take precedence over the
40default typemaps. This option may be used multiple times, with the last
41typemap having the highest precedence.
42
8e07c86e 43=item B<-v>
44
45Prints the I<xsubpp> version number to standard output, then exits.
46
8fc38fda 47=item B<-prototypes>
382b8d97 48
8fc38fda 49By default I<xsubpp> will not automatically generate prototype code for
50all xsubs. This flag will enable prototypes.
51
52=item B<-noversioncheck>
53
54Disables the run time test that determines if the object file (derived
55from the C<.xs> file) and the C<.pm> files have the same version
56number.
382b8d97 57
6f1abe2b 58=item B<-nolinenumbers>
59
60Prevents the inclusion of `#line' directives in the output.
61
b207eff1 62=item B<-object_capi>
e3b8966e 63
64Compile code as C in a PERL_OBJECT environment.
65
66back
75f92628 67
68=head1 ENVIRONMENT
69
70No environment variables are used.
71
72=head1 AUTHOR
73
74Larry Wall
75
f06db76b 76=head1 MODIFICATION HISTORY
77
8e07c86e 78See the file F<changes.pod>.
e50aee73 79
75f92628 80=head1 SEE ALSO
81
55a00e51 82perl(1), perlxs(1), perlxstut(1)
75f92628 83
84=cut
93a17b20 85
382b8d97 86require 5.002;
774d564b 87use Cwd;
4230ab3f 88use vars '$cplusplus';
7ad6fb0b 89use vars '%v';
382b8d97 90
01f988be 91use Config;
92
aa689395 93sub Q ;
94
774d564b 95# Global Constants
774d564b 96
cfc02341 97$XSUBPP_version = "1.9507";
aa689395 98
99my ($Is_VMS, $SymSet);
100if ($^O eq 'VMS') {
101 $Is_VMS = 1;
102 # Establish set of global symbols with max length 28, since xsubpp
103 # will later add the 'XS_' prefix.
104 require ExtUtils::XSSymSet;
105 $SymSet = new ExtUtils::XSSymSet 28;
106}
8fc38fda 107
c07a80fd 108$FH = 'File0000' ;
8fc38fda 109
6f1abe2b 110$usage = "Usage: xsubpp [-v] [-C++] [-except] [-prototypes] [-noversioncheck] [-nolinenumbers] [-s pattern] [-typemap typemap]... file.xs\n";
f06db76b 111
382b8d97 112$proto_re = "[" . quotemeta('\$%&*@;') . "]" ;
01f988be 113# mjn
114$OBJ = 1 if $Config{'ccflags'} =~ /PERL_OBJECT/i;
93a17b20 115
8e07c86e 116$except = "";
8fc38fda 117$WantPrototypes = -1 ;
118$WantVersionChk = 1 ;
119$ProtoUsed = 0 ;
6f1abe2b 120$WantLineNumbers = 1 ;
8e07c86e 121SWITCH: while (@ARGV and $ARGV[0] =~ /^-./) {
93a17b20 122 $flag = shift @ARGV;
e50aee73 123 $flag =~ s/^-// ;
ff68c719 124 $spat = quotemeta shift, next SWITCH if $flag eq 's';
8990e307 125 $cplusplus = 1, next SWITCH if $flag eq 'C++';
382b8d97 126 $WantPrototypes = 0, next SWITCH if $flag eq 'noprototypes';
127 $WantPrototypes = 1, next SWITCH if $flag eq 'prototypes';
8fc38fda 128 $WantVersionChk = 0, next SWITCH if $flag eq 'noversioncheck';
129 $WantVersionChk = 1, next SWITCH if $flag eq 'versioncheck';
b207eff1 130 $WantCAPI = 1, next SWITCH if $flag eq 'object_capi';
8e07c86e 131 $except = " TRY", next SWITCH if $flag eq 'except';
8990e307 132 push(@tm,shift), next SWITCH if $flag eq 'typemap';
6f1abe2b 133 $WantLineNumbers = 0, next SWITCH if $flag eq 'nolinenumbers';
134 $WantLineNumbers = 1, next SWITCH if $flag eq 'linenumbers';
8e07c86e 135 (print "xsubpp version $XSUBPP_version\n"), exit
136 if $flag eq 'v';
93a17b20 137 die $usage;
138}
8fc38fda 139if ($WantPrototypes == -1)
140 { $WantPrototypes = 0}
141else
142 { $ProtoUsed = 1 }
143
144
8990e307 145@ARGV == 1 or die $usage;
c2960299 146($dir, $filename) = $ARGV[0] =~ m#(.*)/(.*)#
57497940 147 or ($dir, $filename) = $ARGV[0] =~ m#(.*)\\(.*)#
c2960299 148 or ($dir, $filename) = $ARGV[0] =~ m#(.*[>\]])(.*)#
8990e307 149 or ($dir, $filename) = ('.', $ARGV[0]);
150chdir($dir);
774d564b 151$pwd = cwd();
8fc38fda 152
153++ $IncludedFiles{$ARGV[0]} ;
93a17b20 154
4230ab3f 155my(@XSStack) = ({type => 'none'}); # Stack of conditionals and INCLUDEs
156my($XSS_work_idx, $cpp_next_tmp) = (0, "XSubPPtmpAAAA");
aa689395 157
4230ab3f 158
f06db76b 159sub TrimWhitespace
160{
161 $_[0] =~ s/^\s+|\s+$//go ;
162}
163
164sub TidyType
165{
166 local ($_) = @_ ;
167
168 # rationalise any '*' by joining them into bunches and removing whitespace
169 s#\s*(\*+)\s*#$1#g;
e50aee73 170 s#(\*+)# $1 #g ;
f06db76b 171
172 # change multiple whitespace into a single space
173 s/\s+/ /g ;
174
175 # trim leading & trailing whitespace
176 TrimWhitespace($_) ;
177
178 $_ ;
179}
180
93a17b20 181$typemap = shift @ARGV;
8990e307 182foreach $typemap (@tm) {
183 die "Can't find $typemap in $pwd\n" unless -r $typemap;
93a17b20 184}
748a9306 185unshift @tm, qw(../../../../lib/ExtUtils/typemap ../../../lib/ExtUtils/typemap
186 ../../lib/ExtUtils/typemap ../../../typemap ../../typemap
187 ../typemap typemap);
8990e307 188foreach $typemap (@tm) {
f06db76b 189 next unless -e $typemap ;
190 # skip directories, binary files etc.
191 warn("Warning: ignoring non-text typemap file '$typemap'\n"), next
192 unless -T $typemap ;
193 open(TYPEMAP, $typemap)
194 or warn ("Warning: could not open typemap file '$typemap': $!\n"), next;
e50aee73 195 $mode = 'Typemap';
c2960299 196 $junk = "" ;
8990e307 197 $current = \$junk;
198 while (<TYPEMAP>) {
e50aee73 199 next if /^\s*#/;
e1f0c0aa 200 my $line_no = $. + 1;
8e07c86e 201 if (/^INPUT\s*$/) { $mode = 'Input'; $current = \$junk; next; }
202 if (/^OUTPUT\s*$/) { $mode = 'Output'; $current = \$junk; next; }
203 if (/^TYPEMAP\s*$/) { $mode = 'Typemap'; $current = \$junk; next; }
e50aee73 204 if ($mode eq 'Typemap') {
205 chomp;
f06db76b 206 my $line = $_ ;
207 TrimWhitespace($_) ;
208 # skip blank lines and comment lines
209 next if /^$/ or /^#/ ;
382b8d97 210 my($type,$kind, $proto) = /^\s*(.*?\S)\s+(\S+)\s*($proto_re*)\s*$/ or
211 warn("Warning: File '$typemap' Line $. '$line' TYPEMAP entry needs 2 or 3 columns\n"), next;
212 $type = TidyType($type) ;
213 $type_kind{$type} = $kind ;
214 # prototype defaults to '$'
93d3b392 215 $proto = "\$" unless $proto ;
382b8d97 216 warn("Warning: File '$typemap' Line $. '$line' Invalid prototype '$proto'\n")
217 unless ValidProtoString($proto) ;
218 $proto_letter{$type} = C_string($proto) ;
8e07c86e 219 }
220 elsif (/^\s/) {
221 $$current .= $_;
463ee0b2 222 }
e50aee73 223 elsif ($mode eq 'Input') {
8e07c86e 224 s/\s+$//;
225 $input_expr{$_} = '';
226 $current = \$input_expr{$_};
93a17b20 227 }
8990e307 228 else {
8e07c86e 229 s/\s+$//;
230 $output_expr{$_} = '';
231 $current = \$output_expr{$_};
93a17b20 232 }
8990e307 233 }
234 close(TYPEMAP);
235}
93a17b20 236
8990e307 237foreach $key (keys %input_expr) {
238 $input_expr{$key} =~ s/\n+$//;
239}
93a17b20 240
8e07c86e 241$END = "!End!\n\n"; # "impossible" keyword (multiple newline)
242
243# Match an XS keyword
382b8d97 244$BLOCK_re= '\s*(' . join('|', qw(
245 REQUIRE BOOT CASE PREINIT INPUT INIT CODE PPCODE OUTPUT
8fc38fda 246 CLEANUP ALIAS PROTOTYPES PROTOTYPE VERSIONCHECK INCLUDE
cfc02341 247 SCOPE INTERFACE INTERFACE_MACRO C_ARGS
382b8d97 248 )) . "|$END)\\s*:";
8e07c86e 249
250# Input: ($_, @line) == unparsed input.
251# Output: ($_, @line) == (rest of line, following lines).
252# Return: the matched keyword if found, otherwise 0
253sub check_keyword {
254 $_ = shift(@line) while !/\S/ && @line;
255 s/^(\s*)($_[0])\s*:\s*(?:#.*)?/$1/s && $2;
256}
257
258
6f1abe2b 259if ($WantLineNumbers) {
260 {
261 package xsubpp::counter;
262 sub TIEHANDLE {
263 my ($class, $cfile) = @_;
264 my $buf = "";
265 $SECTION_END_MARKER = "#line --- \"$cfile\"";
266 $line_no = 1;
267 bless \$buf;
268 }
269
270 sub PRINT {
271 my $self = shift;
272 for (@_) {
273 $$self .= $_;
274 while ($$self =~ s/^([^\n]*\n)//) {
275 my $line = $1;
276 ++ $line_no;
277 $line =~ s|^\#line\s+---(?=\s)|#line $line_no|;
278 print STDOUT $line;
279 }
280 }
281 }
282
283 sub PRINTF {
284 my $self = shift;
285 my $fmt = shift;
286 $self->PRINT(sprintf($fmt, @_));
287 }
288
289 sub DESTROY {
290 # Not necessary if we're careful to end with a "\n"
291 my $self = shift;
292 print STDOUT $$self;
293 }
294 }
295
296 my $cfile = $filename;
297 $cfile =~ s/\.xs$/.c/i or $cfile .= ".c";
298 tie(*PSEUDO_STDOUT, 'xsubpp::counter', $cfile);
299 select PSEUDO_STDOUT;
300}
301
8e07c86e 302sub print_section {
6f1abe2b 303 # the "do" is required for right semantics
304 do { $_ = shift(@line) } while !/\S/ && @line;
305
306 print("#line ", $line_no[@line_no - @line -1], " \"$filename\"\n")
d3308daf 307 if $WantLineNumbers && !/^\s*#\s*line\b/ && !/^#if XSubPPtmp/;
8e07c86e 308 for (; defined($_) && !/^$BLOCK_re/o; $_ = shift(@line)) {
309 print "$_\n";
310 }
6f1abe2b 311 print "$xsubpp::counter::SECTION_END_MARKER\n" if $WantLineNumbers;
8e07c86e 312}
313
cfc02341 314sub merge_section {
315 my $in = '';
316
317 while (!/\S/ && @line) {
318 $_ = shift(@line);
319 }
320
321 for (; defined($_) && !/^$BLOCK_re/o; $_ = shift(@line)) {
322 $in .= "$_\n";
323 }
324 chomp $in;
325 return $in;
326}
327
8fc38fda 328sub process_keyword($)
329{
330 my($pattern) = @_ ;
331 my $kwd ;
332
333 &{"${kwd}_handler"}()
334 while $kwd = check_keyword($pattern) ;
335}
336
8e07c86e 337sub CASE_handler {
338 blurt ("Error: `CASE:' after unconditional `CASE:'")
339 if $condnum && $cond eq '';
340 $cond = $_;
341 TrimWhitespace($cond);
342 print " ", ($condnum++ ? " else" : ""), ($cond ? " if ($cond)\n" : "\n");
343 $_ = '' ;
344}
345
346sub INPUT_handler {
347 for (; !/^$BLOCK_re/o; $_ = shift(@line)) {
348 last if /^\s*NOT_IMPLEMENTED_YET/;
349 next unless /\S/; # skip blank lines
350
351 TrimWhitespace($_) ;
352 my $line = $_ ;
353
354 # remove trailing semicolon if no initialisation
7ad6fb0b 355 s/\s*;$//g unless /[=;+].*\S/ ;
8e07c86e 356
357 # check for optional initialisation code
358 my $var_init = '' ;
7ad6fb0b 359 $var_init = $1 if s/\s*([=;+].*)$//s ;
8e07c86e 360 $var_init =~ s/"/\\"/g;
361
362 s/\s+/ /g;
363 my ($var_type, $var_addr, $var_name) = /^(.*?[^& ]) *(\&?) *\b(\w+)$/s
364 or blurt("Error: invalid argument declaration '$line'"), next;
365
366 # Check for duplicate definitions
367 blurt ("Error: duplicate definition of argument '$var_name' ignored"), next
368 if $arg_list{$var_name} ++ ;
369
370 $thisdone |= $var_name eq "THIS";
371 $retvaldone |= $var_name eq "RETVAL";
372 $var_types{$var_name} = $var_type;
373 print "\t" . &map_type($var_type);
374 $var_num = $args_match{$var_name};
382b8d97 375
8fc38fda 376 $proto_arg[$var_num] = ProtoString($var_type)
377 if $var_num ;
8e07c86e 378 if ($var_addr) {
379 $var_addr{$var_name} = 1;
380 $func_args =~ s/\b($var_name)\b/&$1/;
381 }
7ad6fb0b 382 if ($var_init =~ /^[=;]\s*NO_INIT\s*;?\s*$/) {
8e07c86e 383 print "\t$var_name;\n";
384 } elsif ($var_init =~ /\S/) {
7ad6fb0b 385 &output_init($var_type, $var_num, $var_name, $var_init);
8e07c86e 386 } elsif ($var_num) {
387 # generate initialization code
388 &generate_init($var_type, $var_num, $var_name);
389 } else {
390 print ";\n";
391 }
392 }
393}
394
395sub OUTPUT_handler {
396 for (; !/^$BLOCK_re/o; $_ = shift(@line)) {
397 next unless /\S/;
ef50df4b 398 if (/^\s*SETMAGIC\s*:\s*(ENABLE|DISABLE)\s*/) {
399 $DoSetMagic = ($1 eq "ENABLE" ? 1 : 0);
400 next;
401 }
8e07c86e 402 my ($outarg, $outcode) = /^\s*(\S+)\s*(.*?)\s*$/s ;
403 blurt ("Error: duplicate OUTPUT argument '$outarg' ignored"), next
404 if $outargs{$outarg} ++ ;
405 if (!$gotRETVAL and $outarg eq 'RETVAL') {
406 # deal with RETVAL last
407 $RETVAL_code = $outcode ;
408 $gotRETVAL = 1 ;
409 next ;
410 }
411 blurt ("Error: OUTPUT $outarg not an argument"), next
412 unless defined($args_match{$outarg});
413 blurt("Error: No input definition for OUTPUT argument '$outarg' - ignored"), next
414 unless defined $var_types{$outarg} ;
f78230ad 415 $var_num = $args_match{$outarg};
8e07c86e 416 if ($outcode) {
417 print "\t$outcode\n";
f78230ad 418 print "\tSvSETMAGIC(ST(" , $var_num-1 , "));\n" if $DoSetMagic;
8e07c86e 419 } else {
ef50df4b 420 &generate_output($var_types{$outarg}, $var_num, $outarg, $DoSetMagic);
8e07c86e 421 }
422 }
423}
424
cfc02341 425sub C_ARGS_handler() {
426 my $in = merge_section();
427
428 TrimWhitespace($in);
429 $func_args = $in;
430}
431
432sub INTERFACE_MACRO_handler() {
433 my $in = merge_section();
434
435 TrimWhitespace($in);
436 if ($in =~ /\s/) { # two
437 ($interface_macro, $interface_macro_set) = split ' ', $in;
438 } else {
439 $interface_macro = $in;
440 $interface_macro_set = 'UNKNOWN_CVT'; # catch later
441 }
442 $interface = 1; # local
443 $Interfaces = 1; # global
444}
445
446sub INTERFACE_handler() {
447 my $in = merge_section();
448
449 TrimWhitespace($in);
450
451 foreach (split /[\s,]+/, $in) {
452 $Interfaces{$_} = $_;
453 }
454 print Q<<"EOF";
455# XSFUNCTION = $interface_macro($ret_type,cv,XSANY.any_dptr);
456EOF
457 $interface = 1; # local
458 $Interfaces = 1; # global
459}
460
8fc38fda 461sub CLEANUP_handler() { print_section() }
462sub PREINIT_handler() { print_section() }
463sub INIT_handler() { print_section() }
464
8e07c86e 465sub GetAliases
466{
467 my ($line) = @_ ;
468 my ($orig) = $line ;
469 my ($alias) ;
470 my ($value) ;
471
472 # Parse alias definitions
473 # format is
474 # alias = value alias = value ...
475
476 while ($line =~ s/^\s*([\w:]+)\s*=\s*(\w+)\s*//) {
477 $alias = $1 ;
478 $orig_alias = $alias ;
479 $value = $2 ;
480
481 # check for optional package definition in the alias
482 $alias = $Packprefix . $alias if $alias !~ /::/ ;
483
484 # check for duplicate alias name & duplicate value
485 Warn("Warning: Ignoring duplicate alias '$orig_alias'")
4230ab3f 486 if defined $XsubAliases{$alias} ;
8e07c86e 487
4230ab3f 488 Warn("Warning: Aliases '$orig_alias' and '$XsubAliasValues{$value}' have identical values")
489 if $XsubAliasValues{$value} ;
8e07c86e 490
4230ab3f 491 $XsubAliases = 1;
492 $XsubAliases{$alias} = $value ;
493 $XsubAliasValues{$value} = $orig_alias ;
8e07c86e 494 }
495
496 blurt("Error: Cannot parse ALIAS definitions from '$orig'")
497 if $line ;
498}
499
382b8d97 500sub ALIAS_handler ()
8e07c86e 501{
502 for (; !/^$BLOCK_re/o; $_ = shift(@line)) {
503 next unless /\S/;
504 TrimWhitespace($_) ;
505 GetAliases($_) if $_ ;
506 }
507}
508
382b8d97 509sub REQUIRE_handler ()
8e07c86e 510{
511 # the rest of the current line should contain a version number
512 my ($Ver) = $_ ;
513
514 TrimWhitespace($Ver) ;
515
516 death ("Error: REQUIRE expects a version number")
517 unless $Ver ;
518
519 # check that the version number is of the form n.n
520 death ("Error: REQUIRE: expected a number, got '$Ver'")
521 unless $Ver =~ /^\d+(\.\d*)?/ ;
522
523 death ("Error: xsubpp $Ver (or better) required--this is only $XSUBPP_version.")
524 unless $XSUBPP_version >= $Ver ;
525}
526
8fc38fda 527sub VERSIONCHECK_handler ()
528{
529 # the rest of the current line should contain either ENABLE or
530 # DISABLE
531
532 TrimWhitespace($_) ;
533
534 # check for ENABLE/DISABLE
535 death ("Error: VERSIONCHECK: ENABLE/DISABLE")
536 unless /^(ENABLE|DISABLE)/i ;
537
538 $WantVersionChk = 1 if $1 eq 'ENABLE' ;
539 $WantVersionChk = 0 if $1 eq 'DISABLE' ;
540
541}
542
382b8d97 543sub PROTOTYPE_handler ()
544{
7d41bd0a 545 my $specified ;
546
c07a80fd 547 death("Error: Only 1 PROTOTYPE definition allowed per xsub")
548 if $proto_in_this_xsub ++ ;
549
382b8d97 550 for (; !/^$BLOCK_re/o; $_ = shift(@line)) {
551 next unless /\S/;
7d41bd0a 552 $specified = 1 ;
382b8d97 553 TrimWhitespace($_) ;
554 if ($_ eq 'DISABLE') {
555 $ProtoThisXSUB = 0
556 }
557 elsif ($_ eq 'ENABLE') {
558 $ProtoThisXSUB = 1
559 }
560 else {
561 # remove any whitespace
562 s/\s+//g ;
563 death("Error: Invalid prototype '$_'")
564 unless ValidProtoString($_) ;
565 $ProtoThisXSUB = C_string($_) ;
566 }
567 }
c07a80fd 568
7d41bd0a 569 # If no prototype specified, then assume empty prototype ""
570 $ProtoThisXSUB = 2 unless $specified ;
571
8fc38fda 572 $ProtoUsed = 1 ;
c07a80fd 573
382b8d97 574}
575
db3b9414 576sub SCOPE_handler ()
577{
578 death("Error: Only 1 SCOPE declaration allowed per xsub")
579 if $scope_in_this_xsub ++ ;
580
581 for (; !/^$BLOCK_re/o; $_ = shift(@line)) {
582 next unless /\S/;
583 TrimWhitespace($_) ;
584 if ($_ =~ /^DISABLE/i) {
585 $ScopeThisXSUB = 0
586 }
587 elsif ($_ =~ /^ENABLE/i) {
588 $ScopeThisXSUB = 1
589 }
590 }
591
592}
593
382b8d97 594sub PROTOTYPES_handler ()
595{
596 # the rest of the current line should contain either ENABLE or
597 # DISABLE
598
599 TrimWhitespace($_) ;
600
601 # check for ENABLE/DISABLE
602 death ("Error: PROTOTYPES: ENABLE/DISABLE")
603 unless /^(ENABLE|DISABLE)/i ;
604
605 $WantPrototypes = 1 if $1 eq 'ENABLE' ;
606 $WantPrototypes = 0 if $1 eq 'DISABLE' ;
8fc38fda 607 $ProtoUsed = 1 ;
382b8d97 608
609}
610
8fc38fda 611sub INCLUDE_handler ()
612{
613 # the rest of the current line should contain a valid filename
614
615 TrimWhitespace($_) ;
616
8fc38fda 617 death("INCLUDE: filename missing")
618 unless $_ ;
619
620 death("INCLUDE: output pipe is illegal")
621 if /^\s*\|/ ;
622
623 # simple minded recursion detector
624 death("INCLUDE loop detected")
625 if $IncludedFiles{$_} ;
626
627 ++ $IncludedFiles{$_} unless /\|\s*$/ ;
628
629 # Save the current file context.
4230ab3f 630 push(@XSStack, {
631 type => 'file',
8fc38fda 632 LastLine => $lastline,
633 LastLineNo => $lastline_no,
634 Line => \@line,
635 LineNo => \@line_no,
636 Filename => $filename,
c07a80fd 637 Handle => $FH,
8fc38fda 638 }) ;
639
c07a80fd 640 ++ $FH ;
8fc38fda 641
642 # open the new file
c07a80fd 643 open ($FH, "$_") or death("Cannot open '$_': $!") ;
8fc38fda 644
645 print Q<<"EOF" ;
646#
647#/* INCLUDE: Including '$_' from '$filename' */
648#
649EOF
650
8fc38fda 651 $filename = $_ ;
652
c07a80fd 653 # Prime the pump by reading the first
654 # non-blank line
655
656 # skip leading blank lines
657 while (<$FH>) {
658 last unless /^\s*$/ ;
659 }
660
661 $lastline = $_ ;
8fc38fda 662 $lastline_no = $. ;
663
664}
665
666sub PopFile()
667{
4230ab3f 668 return 0 unless $XSStack[-1]{type} eq 'file' ;
669
670 my $data = pop @XSStack ;
8fc38fda 671 my $ThisFile = $filename ;
672 my $isPipe = ($filename =~ /\|\s*$/) ;
673
674 -- $IncludedFiles{$filename}
675 unless $isPipe ;
676
c07a80fd 677 close $FH ;
8fc38fda 678
c07a80fd 679 $FH = $data->{Handle} ;
8fc38fda 680 $filename = $data->{Filename} ;
681 $lastline = $data->{LastLine} ;
682 $lastline_no = $data->{LastLineNo} ;
683 @line = @{ $data->{Line} } ;
684 @line_no = @{ $data->{LineNo} } ;
4230ab3f 685
8fc38fda 686 if ($isPipe and $? ) {
687 -- $lastline_no ;
688 print STDERR "Error reading from pipe '$ThisFile': $! in $filename, line $lastline_no\n" ;
689 exit 1 ;
690 }
691
692 print Q<<"EOF" ;
693#
694#/* INCLUDE: Returning to '$filename' from '$ThisFile' */
695#
696EOF
697
698 return 1 ;
699}
700
382b8d97 701sub ValidProtoString ($)
702{
703 my($string) = @_ ;
704
705 if ( $string =~ /^$proto_re+$/ ) {
706 return $string ;
707 }
708
709 return 0 ;
710}
711
712sub C_string ($)
713{
714 my($string) = @_ ;
715
716 $string =~ s[\\][\\\\]g ;
717 $string ;
718}
719
720sub ProtoString ($)
721{
722 my ($type) = @_ ;
723
93d3b392 724 $proto_letter{$type} or "\$" ;
382b8d97 725}
726
8e07c86e 727sub check_cpp {
728 my @cpp = grep(/^\#\s*(?:if|e\w+)/, @line);
729 if (@cpp) {
730 my ($cpp, $cpplevel);
731 for $cpp (@cpp) {
732 if ($cpp =~ /^\#\s*if/) {
733 $cpplevel++;
734 } elsif (!$cpplevel) {
735 Warn("Warning: #else/elif/endif without #if in this function");
4230ab3f 736 print STDERR " (precede it with a blank line if the matching #if is outside the function)\n"
737 if $XSStack[-1]{type} eq 'if';
8e07c86e 738 return;
739 } elsif ($cpp =~ /^\#\s*endif/) {
740 $cpplevel--;
741 }
742 }
743 Warn("Warning: #if without #endif in this function") if $cpplevel;
744 }
745}
746
747
8990e307 748sub Q {
e50aee73 749 my($text) = @_;
4633a7c4 750 $text =~ s/^#//gm;
2304df62 751 $text =~ s/\[\[/{/g;
752 $text =~ s/\]\]/}/g;
8990e307 753 $text;
93a17b20 754}
755
c07a80fd 756open($FH, $filename) or die "cannot open $filename: $!\n";
c2960299 757
f06db76b 758# Identify the version of xsubpp used
f06db76b 759print <<EOM ;
e50aee73 760/*
761 * This file was generated automatically by xsubpp version $XSUBPP_version from the
93d3b392 762 * contents of $filename. Do not edit this file, edit $filename instead.
e50aee73 763 *
764 * ANY CHANGES MADE HERE WILL BE LOST!
f06db76b 765 *
766 */
e50aee73 767
f06db76b 768EOM
6f1abe2b 769
770
771print("#line 1 \"$filename\"\n")
772 if $WantLineNumbers;
f06db76b 773
c07a80fd 774while (<$FH>) {
e50aee73 775 last if ($Module, $Package, $Prefix) =
776 /^MODULE\s*=\s*([\w:]+)(?:\s+PACKAGE\s*=\s*([\w:]+))?(?:\s+PREFIX\s*=\s*(\S+))?\s*$/;
01f988be 777
778 if ($OBJ) {
779 s/#if(?:def|\s+defined)\s+(\(__cplusplus\)|__cplusplus)/#if defined(__cplusplus) && !defined(PERL_OBJECT)/;
780 }
a0d0e21e 781 print $_;
93a17b20 782}
e50aee73 783&Exit unless defined $_;
784
cfc02341 785print "$xsubpp::counter::SECTION_END_MARKER\n" if $WantLineNumbers;
786
8fc38fda 787$lastline = $_;
788$lastline_no = $.;
93a17b20 789
c07a80fd 790# Read next xsub into @line from ($lastline, <$FH>).
2304df62 791sub fetch_para {
792 # parse paragraph
4230ab3f 793 death ("Error: Unterminated `#if/#ifdef/#ifndef'")
794 if !defined $lastline && $XSStack[-1]{type} eq 'if';
2304df62 795 @line = ();
c2960299 796 @line_no = () ;
4230ab3f 797 return PopFile() if !defined $lastline;
e50aee73 798
799 if ($lastline =~
800 /^MODULE\s*=\s*([\w:]+)(?:\s+PACKAGE\s*=\s*([\w:]+))?(?:\s+PREFIX\s*=\s*(\S+))?\s*$/) {
801 $Module = $1;
8e07c86e 802 $Package = defined($2) ? $2 : ''; # keep -w happy
803 $Prefix = defined($3) ? $3 : ''; # keep -w happy
ff68c719 804 $Prefix = quotemeta $Prefix ;
e50aee73 805 ($Module_cname = $Module) =~ s/\W/_/g;
8e07c86e 806 ($Packid = $Package) =~ tr/:/_/;
e50aee73 807 $Packprefix = $Package;
8e07c86e 808 $Packprefix .= "::" if $Packprefix ne "";
2304df62 809 $lastline = "";
e50aee73 810 }
811
812 for(;;) {
813 if ($lastline !~ /^\s*#/ ||
4230ab3f 814 # CPP directives:
815 # ANSI: if ifdef ifndef elif else endif define undef
816 # line error pragma
817 # gcc: warning include_next
818 # obj-c: import
819 # others: ident (gcc notes that some cpps have this one)
820 $lastline =~ /^#[ \t]*(?:(?:if|ifn?def|elif|else|endif|define|undef|pragma|error|warning|line\s+\d+|ident)\b|(?:include(?:_next)?|import)\s*["<].*[>"])/) {
e50aee73 821 last if $lastline =~ /^\S/ && @line && $line[-1] eq "";
822 push(@line, $lastline);
823 push(@line_no, $lastline_no) ;
93a17b20 824 }
e50aee73 825
826 # Read next line and continuation lines
c07a80fd 827 last unless defined($lastline = <$FH>);
e50aee73 828 $lastline_no = $.;
829 my $tmp_line;
830 $lastline .= $tmp_line
c07a80fd 831 while ($lastline =~ /\\$/ && defined($tmp_line = <$FH>));
e50aee73 832
8e07c86e 833 chomp $lastline;
e50aee73 834 $lastline =~ s/^\s+$//;
2304df62 835 }
e50aee73 836 pop(@line), pop(@line_no) while @line && $line[-1] eq "";
e50aee73 837 1;
2304df62 838}
93a17b20 839
c2960299 840PARAGRAPH:
8e07c86e 841while (fetch_para()) {
e50aee73 842 # Print initial preprocessor statements and blank lines
4230ab3f 843 while (@line && $line[0] !~ /^[^\#]/) {
844 my $line = shift(@line);
845 print $line, "\n";
846 next unless $line =~ /^\#\s*((if)(?:n?def)?|elsif|else|endif)\b/;
847 my $statement = $+;
848 if ($statement eq 'if') {
849 $XSS_work_idx = @XSStack;
850 push(@XSStack, {type => 'if'});
851 } else {
852 death ("Error: `$statement' with no matching `if'")
853 if $XSStack[-1]{type} ne 'if';
854 if ($XSStack[-1]{varname}) {
855 push(@InitFileCode, "#endif\n");
856 push(@BootCode, "#endif");
857 }
858
859 my(@fns) = keys %{$XSStack[-1]{functions}};
860 if ($statement ne 'endif') {
861 # Hide the functions defined in other #if branches, and reset.
862 @{$XSStack[-1]{other_functions}}{@fns} = (1) x @fns;
863 @{$XSStack[-1]}{qw(varname functions)} = ('', {});
864 } else {
865 my($tmp) = pop(@XSStack);
866 0 while (--$XSS_work_idx
867 && $XSStack[$XSS_work_idx]{type} ne 'if');
868 # Keep all new defined functions
869 push(@fns, keys %{$tmp->{other_functions}});
870 @{$XSStack[$XSS_work_idx]{functions}}{@fns} = (1) x @fns;
871 }
872 }
873 }
e50aee73 874
875 next PARAGRAPH unless @line;
876
4230ab3f 877 if ($XSS_work_idx && !$XSStack[$XSS_work_idx]{varname}) {
878 # We are inside an #if, but have not yet #defined its xsubpp variable.
879 print "#define $cpp_next_tmp 1\n\n";
880 push(@InitFileCode, "#if $cpp_next_tmp\n");
881 push(@BootCode, "#if $cpp_next_tmp");
882 $XSStack[$XSS_work_idx]{varname} = $cpp_next_tmp++;
883 }
884
55497cff 885 death ("Code is not inside a function"
886 ." (maybe last function was ended by a blank line "
887 ." followed by a a statement on column one?)")
e50aee73 888 if $line[0] =~ /^\s/;
889
2304df62 890 # initialize info arrays
891 undef(%args_match);
892 undef(%var_types);
893 undef(%var_addr);
894 undef(%defaults);
895 undef($class);
896 undef($static);
897 undef($elipsis);
f06db76b 898 undef($wantRETVAL) ;
899 undef(%arg_list) ;
382b8d97 900 undef(@proto_arg) ;
c07a80fd 901 undef($proto_in_this_xsub) ;
db3b9414 902 undef($scope_in_this_xsub) ;
cfc02341 903 undef($interface);
904 $interface_macro = 'XSINTERFACE_FUNC' ;
905 $interface_macro_set = 'XSINTERFACE_FUNC_SET' ;
382b8d97 906 $ProtoThisXSUB = $WantPrototypes ;
db3b9414 907 $ScopeThisXSUB = 0;
2304df62 908
8e07c86e 909 $_ = shift(@line);
8fc38fda 910 while ($kwd = check_keyword("REQUIRE|PROTOTYPES|VERSIONCHECK|INCLUDE")) {
911 &{"${kwd}_handler"}() ;
8e07c86e 912 next PARAGRAPH unless @line ;
913 $_ = shift(@line);
914 }
c2960299 915
8e07c86e 916 if (check_keyword("BOOT")) {
917 &check_cpp;
6f1abe2b 918 push (@BootCode, "#line $line_no[@line_no - @line] \"$filename\"")
919 if $WantLineNumbers && $line[0] !~ /^\s*#\s*line\b/;
920 push (@BootCode, @line, "") ;
c2960299 921 next PARAGRAPH ;
a0d0e21e 922 }
c2960299 923
8e07c86e 924
925 # extract return type, function name and arguments
cfc02341 926 ($ret_type) = TidyType($_);
8e07c86e 927
c2960299 928 # a function definition needs at least 2 lines
929 blurt ("Error: Function definition too short '$ret_type'"), next PARAGRAPH
930 unless @line ;
931
8e07c86e 932 $static = 1 if $ret_type =~ s/^static\s+//;
933
2304df62 934 $func_header = shift(@line);
c2960299 935 blurt ("Error: Cannot parse function definition from '$func_header'"), next PARAGRAPH
f480b56a 936 unless $func_header =~ /^(?:([\w:]*)::)?(\w+)\s*\(\s*(.*?)\s*\)\s*(const)?\s*$/s;
c2960299 937
8e07c86e 938 ($class, $func_name, $orig_args) = ($1, $2, $3) ;
f480b56a 939 $class = "$4 $class" if $4;
2304df62 940 ($pname = $func_name) =~ s/^($Prefix)?/$Packprefix/;
ff68c719 941 ($clean_func_name = $func_name) =~ s/^$Prefix//;
942 $Full_func_name = "${Packid}_$clean_func_name";
ff0cee69 943 if ($Is_VMS) { $Full_func_name = $SymSet->addsym($Full_func_name); }
c2960299 944
945 # Check for duplicate function definition
4230ab3f 946 for $tmp (@XSStack) {
947 next unless defined $tmp->{functions}{$Full_func_name};
ff68c719 948 Warn("Warning: duplicate function definition '$clean_func_name' detected");
4230ab3f 949 last;
8e07c86e 950 }
4230ab3f 951 $XSStack[$XSS_work_idx]{functions}{$Full_func_name} ++ ;
cfc02341 952 %XsubAliases = %XsubAliasValues = %Interfaces = ();
ef50df4b 953 $DoSetMagic = 1;
c2960299 954
2304df62 955 @args = split(/\s*,\s*/, $orig_args);
a0d0e21e 956 if (defined($class)) {
683d4eee 957 my $arg0 = ((defined($static) or $func_name eq 'new')
958 ? "CLASS" : "THIS");
8e07c86e 959 unshift(@args, $arg0);
960 ($orig_args = "$arg0, $orig_args") =~ s/^$arg0, $/$arg0/;
2304df62 961 }
962 $orig_args =~ s/"/\\"/g;
963 $min_args = $num_args = @args;
964 foreach $i (0..$num_args-1) {
965 if ($args[$i] =~ s/\.\.\.//) {
966 $elipsis = 1;
967 $min_args--;
c2960299 968 if ($args[$i] eq '' && $i == $num_args - 1) {
2304df62 969 pop(@args);
970 last;
971 }
972 }
8e07c86e 973 if ($args[$i] =~ /^([^=]*[^\s=])\s*=\s*(.*)/s) {
2304df62 974 $min_args--;
975 $args[$i] = $1;
976 $defaults{$args[$i]} = $2;
977 $defaults{$args[$i]} =~ s/"/\\"/g;
978 }
93d3b392 979 $proto_arg[$i+1] = "\$" ;
2304df62 980 }
a0d0e21e 981 if (defined($class)) {
2304df62 982 $func_args = join(", ", @args[1..$#args]);
983 } else {
984 $func_args = join(", ", @args);
985 }
986 @args_match{@args} = 1..@args;
987
8e07c86e 988 $PPCODE = grep(/^\s*PPCODE\s*:/, @line);
93d3b392 989 $CODE = grep(/^\s*CODE\s*:/, @line);
6c5fb52b 990 # Detect CODE: blocks which use ST(n)= or XST_m*(n,v)
991 # to set explicit return values.
992 $EXPLICIT_RETURN = ($CODE &&
993 ("@line" =~ /(\bST\s*\([^;]*=) | (\bXST_m\w+\s*\()/x ));
8e07c86e 994 $ALIAS = grep(/^\s*ALIAS\s*:/, @line);
cfc02341 995 $INTERFACE = grep(/^\s*INTERFACE\s*:/, @line);
8e07c86e 996
2304df62 997 # print function header
a0d0e21e 998 print Q<<"EOF";
ff68c719 999#XS(XS_${Full_func_name})
2304df62 1000#[[
a0d0e21e 1001# dXSARGS;
93a17b20 1002EOF
8e07c86e 1003 print Q<<"EOF" if $ALIAS ;
1004# dXSI32;
1005EOF
cfc02341 1006 print Q<<"EOF" if $INTERFACE ;
1007# dXSFUNCTION($ret_type);
1008EOF
2304df62 1009 if ($elipsis) {
8e07c86e 1010 $cond = ($min_args ? qq(items < $min_args) : 0);
2304df62 1011 }
1012 elsif ($min_args == $num_args) {
1013 $cond = qq(items != $min_args);
1014 }
1015 else {
1016 $cond = qq(items < $min_args || items > $num_args);
1017 }
8990e307 1018
2304df62 1019 print Q<<"EOF" if $except;
1020# char errbuf[1024];
1021# *errbuf = '\0';
1022EOF
1023
8e07c86e 1024 if ($ALIAS)
1025 { print Q<<"EOF" if $cond }
1026# if ($cond)
1027# croak("Usage: %s($orig_args)", GvNAME(CvGV(cv)));
1028EOF
1029 else
1030 { print Q<<"EOF" if $cond }
1031# if ($cond)
8990e307 1032# croak("Usage: $pname($orig_args)");
93a17b20 1033EOF
1034
a0d0e21e 1035 print Q<<"EOF" if $PPCODE;
1036# SP -= items;
1037EOF
1038
2304df62 1039 # Now do a block of some sort.
93a17b20 1040
2304df62 1041 $condnum = 0;
8e07c86e 1042 $cond = ''; # last CASE: condidional
1043 push(@line, "$END:");
1044 push(@line_no, $line_no[-1]);
1045 $_ = '';
1046 &check_cpp;
2304df62 1047 while (@line) {
8e07c86e 1048 &CASE_handler if check_keyword("CASE");
1049 print Q<<"EOF";
1050# $except [[
93a17b20 1051EOF
1052
1053 # do initialization of input variables
1054 $thisdone = 0;
1055 $retvaldone = 0;
463ee0b2 1056 $deferred = "";
c2960299 1057 %arg_list = () ;
1058 $gotRETVAL = 0;
f06db76b 1059
8fc38fda 1060 INPUT_handler() ;
cfc02341 1061 process_keyword("INPUT|PREINIT|INTERFACE_MACRO|C_ARGS|ALIAS|PROTOTYPE|SCOPE") ;
8fc38fda 1062
db3b9414 1063 print Q<<"EOF" if $ScopeThisXSUB;
1064# ENTER;
1065# [[
1066EOF
1067
a0d0e21e 1068 if (!$thisdone && defined($class)) {
683d4eee 1069 if (defined($static) or $func_name eq 'new') {
a0d0e21e 1070 print "\tchar *";
1071 $var_types{"CLASS"} = "char *";
1072 &generate_init("char *", 1, "CLASS");
1073 }
1074 else {
93a17b20 1075 print "\t$class *";
1076 $var_types{"THIS"} = "$class *";
1077 &generate_init("$class *", 1, "THIS");
a0d0e21e 1078 }
93a17b20 1079 }
1080
1081 # do code
1082 if (/^\s*NOT_IMPLEMENTED_YET/) {
4633a7c4 1083 print "\n\tcroak(\"$pname: not implemented yet\");\n";
1084 $_ = '' ;
93a17b20 1085 } else {
1086 if ($ret_type ne "void") {
1087 print "\t" . &map_type($ret_type) . "\tRETVAL;\n"
1088 if !$retvaldone;
1089 $args_match{"RETVAL"} = 0;
1090 $var_types{"RETVAL"} = $ret_type;
1091 }
db3b9414 1092
8e07c86e 1093 print $deferred;
db3b9414 1094
cfc02341 1095 process_keyword("INIT|ALIAS|PROTOTYPE|INTERFACE_MACRO|INTERFACE|C_ARGS") ;
8e07c86e 1096
1097 if (check_keyword("PPCODE")) {
8fc38fda 1098 print_section();
8e07c86e 1099 death ("PPCODE must be last thing") if @line;
db3b9414 1100 print "\tLEAVE;\n" if $ScopeThisXSUB;
a0d0e21e 1101 print "\tPUTBACK;\n\treturn;\n";
8e07c86e 1102 } elsif (check_keyword("CODE")) {
8fc38fda 1103 print_section() ;
1104 } elsif (defined($class) and $func_name eq "DESTROY") {
a0d0e21e 1105 print "\n\t";
8e07c86e 1106 print "delete THIS;\n";
93a17b20 1107 } else {
1108 print "\n\t";
1109 if ($ret_type ne "void") {
463ee0b2 1110 print "RETVAL = ";
e50aee73 1111 $wantRETVAL = 1;
93a17b20 1112 }
1113 if (defined($static)) {
683d4eee 1114 if ($func_name eq 'new') {
8fc38fda 1115 $func_name = "$class";
8e07c86e 1116 } else {
1117 print "${class}::";
a0d0e21e 1118 }
93a17b20 1119 } elsif (defined($class)) {
683d4eee 1120 if ($func_name eq 'new') {
8fc38fda 1121 $func_name .= " $class";
1122 } else {
93a17b20 1123 print "THIS->";
8fc38fda 1124 }
93a17b20 1125 }
e50aee73 1126 $func_name =~ s/^($spat)//
1127 if defined($spat);
cfc02341 1128 $func_name = 'XSFUNCTION' if $interface;
93a17b20 1129 print "$func_name($func_args);\n";
93a17b20 1130 }
1131 }
1132
1133 # do output variables
8e07c86e 1134 $gotRETVAL = 0;
1135 undef $RETVAL_code ;
1136 undef %outargs ;
8fc38fda 1137 process_keyword("OUTPUT|ALIAS|PROTOTYPE");
f06db76b 1138
1139 # all OUTPUT done, so now push the return value on the stack
8e07c86e 1140 if ($gotRETVAL && $RETVAL_code) {
1141 print "\t$RETVAL_code\n";
1142 } elsif ($gotRETVAL || $wantRETVAL) {
ef50df4b 1143 # RETVAL almost never needs SvSETMAGIC()
1144 &generate_output($ret_type, 0, 'RETVAL', 0);
8e07c86e 1145 }
f06db76b 1146
93a17b20 1147 # do cleanup
8fc38fda 1148 process_keyword("CLEANUP|ALIAS|PROTOTYPE") ;
8e07c86e 1149
db3b9414 1150 print Q<<"EOF" if $ScopeThisXSUB;
1151# ]]
1152EOF
1153 print Q<<"EOF" if $ScopeThisXSUB and not $PPCODE;
1154# LEAVE;
1155EOF
1156
93a17b20 1157 # print function trailer
8e07c86e 1158 print Q<<EOF;
2304df62 1159# ]]
8e07c86e 1160EOF
1161 print Q<<EOF if $except;
8990e307 1162# BEGHANDLERS
1163# CATCHALL
1164# sprintf(errbuf, "%s: %s\\tpropagated", Xname, Xreason);
1165# ENDHANDLERS
93a17b20 1166EOF
8e07c86e 1167 if (check_keyword("CASE")) {
1168 blurt ("Error: No `CASE:' at top of function")
1169 unless $condnum;
1170 $_ = "CASE: $_"; # Restore CASE: label
1171 next;
8990e307 1172 }
8e07c86e 1173 last if $_ eq "$END:";
1174 death(/^$BLOCK_re/o ? "Misplaced `$1:'" : "Junk at end of function");
2304df62 1175 }
a0d0e21e 1176
2304df62 1177 print Q<<EOF if $except;
1178# if (errbuf[0])
1179# croak(errbuf);
1180EOF
a0d0e21e 1181
7c5b83de 1182 if ($ret_type ne "void" or $EXPLICIT_RETURN) {
93d3b392 1183 print Q<<EOF unless $PPCODE;
a0d0e21e 1184# XSRETURN(1);
1185EOF
93d3b392 1186 } else {
1187 print Q<<EOF unless $PPCODE;
1188# XSRETURN_EMPTY;
1189EOF
1190 }
a0d0e21e 1191
2304df62 1192 print Q<<EOF;
2304df62 1193#]]
8990e307 1194#
93a17b20 1195EOF
382b8d97 1196
4230ab3f 1197 my $newXS = "newXS" ;
1198 my $proto = "" ;
1199
382b8d97 1200 # Build the prototype string for the xsub
1201 if ($ProtoThisXSUB) {
4230ab3f 1202 $newXS = "newXSproto";
1203
6f1abe2b 1204 if ($ProtoThisXSUB eq 2) {
4230ab3f 1205 # User has specified empty prototype
1206 $proto = ', ""' ;
1207 }
6f1abe2b 1208 elsif ($ProtoThisXSUB ne 1) {
7d41bd0a 1209 # User has specified a prototype
4230ab3f 1210 $proto = ', "' . $ProtoThisXSUB . '"';
382b8d97 1211 }
1212 else {
1213 my $s = ';';
1214 if ($min_args < $num_args) {
1215 $s = '';
1216 $proto_arg[$min_args] .= ";" ;
1217 }
4230ab3f 1218 push @proto_arg, "$s\@"
382b8d97 1219 if $elipsis ;
1220
4230ab3f 1221 $proto = ', "' . join ("", @proto_arg) . '"';
382b8d97 1222 }
1223 }
1224
4230ab3f 1225 if (%XsubAliases) {
1226 $XsubAliases{$pname} = 0
1227 unless defined $XsubAliases{$pname} ;
1228 while ( ($name, $value) = each %XsubAliases) {
1229 push(@InitFileCode, Q<<"EOF");
1230# cv = newXS(\"$name\", XS_$Full_func_name, file);
1231# XSANY.any_i32 = $value ;
1232EOF
1233 push(@InitFileCode, Q<<"EOF") if $proto;
1234# sv_setpv((SV*)cv$proto) ;
1235EOF
1236 }
cfc02341 1237 }
1238 elsif ($interface) {
1239 while ( ($name, $value) = each %Interfaces) {
1240 $name = "$Package\::$name" unless $name =~ /::/;
1241 push(@InitFileCode, Q<<"EOF");
1242# cv = newXS(\"$name\", XS_$Full_func_name, file);
1243# $interface_macro_set(cv,$value) ;
1244EOF
1245 push(@InitFileCode, Q<<"EOF") if $proto;
1246# sv_setpv((SV*)cv$proto) ;
1247EOF
1248 }
4230ab3f 1249 }
1250 else {
1251 push(@InitFileCode,
1252 " ${newXS}(\"$pname\", XS_$Full_func_name, file$proto);\n");
1253 }
93a17b20 1254}
1255
1256# print initialization routine
7ee8c957 1257
e3b8966e 1258print Q<<"EOF";
e3b8966e 1259##ifdef __cplusplus
1260#extern "C"
1261##endif
7ee8c957 1262EOF
1263
1264if ($WantCAPI) {
1265print Q<<"EOF";
1266##ifdef PERL_CAPI
e3b8966e 1267#XS(boot__CAPI_entry)
7ee8c957 1268##else
e3b8966e 1269EOF
7ee8c957 1270}
1271
8990e307 1272print Q<<"EOF";
a0d0e21e 1273#XS(boot_$Module_cname)
7ee8c957 1274EOF
1275
1276if ($WantCAPI) {
1277print Q<<"EOF";
1278##endif /* PERL_CAPI */
1279EOF
1280}
1281
1282print Q<<"EOF";
2304df62 1283#[[
a0d0e21e 1284# dXSARGS;
8990e307 1285# char* file = __FILE__;
1286#
93a17b20 1287EOF
1288
8fc38fda 1289print Q<<"EOF" if $WantVersionChk ;
1290# XS_VERSION_BOOTCHECK ;
1291#
1292EOF
1293
cfc02341 1294print Q<<"EOF" if defined $XsubAliases or defined $Interfaces ;
8e07c86e 1295# {
1296# CV * cv ;
1297#
1298EOF
1299
4230ab3f 1300print @InitFileCode;
a0d0e21e 1301
cfc02341 1302print Q<<"EOF" if defined $XsubAliases or defined $Interfaces ;
8e07c86e 1303# }
1304EOF
1305
a0d0e21e 1306if (@BootCode)
1307{
6f1abe2b 1308 print "\n /* Initialisation Section */\n\n" ;
1309 @line = @BootCode;
1310 print_section();
8e07c86e 1311 print "\n /* End of Initialisation Section */\n\n" ;
93a17b20 1312}
a0d0e21e 1313
e50aee73 1314print Q<<"EOF";;
3280af22 1315# XSRETURN_YES;
e50aee73 1316#]]
e3b8966e 1317#
1318EOF
1319
1320if ($WantCAPI) {
1321print Q<<"EOF";
7ee8c957 1322##ifdef PERL_CAPI
b207eff1 1323##define XSCAPI(name) void name(CV* cv, void* pPerl)
1324#
e3b8966e 1325##ifdef __cplusplus
1326#extern "C"
1327##endif
1328#XSCAPI(boot_$Module_cname)
1329#[[
1330# SetCPerlObj(pPerl);
1331# boot__CAPI_entry(cv);
1332#]]
7ee8c957 1333##endif /* PERL_CAPI */
e50aee73 1334EOF
e3b8966e 1335}
e50aee73 1336
8fc38fda 1337warn("Please specify prototyping behavior for $filename (see perlxs manual)\n")
1338 unless $ProtoUsed ;
e50aee73 1339&Exit;
1340
93a17b20 1341sub output_init {
7ad6fb0b 1342 local($type, $num, $var, $init) = @_;
a0d0e21e 1343 local($arg) = "ST(" . ($num - 1) . ")";
93a17b20 1344
7ad6fb0b 1345 if( $init =~ /^=/ ) {
1346 eval qq/print "\\t$var $init\\n"/;
1347 warn $@ if $@;
1348 } else {
1349 if( $init =~ s/^\+// && $num ) {
1350 &generate_init($type, $num, $var);
1351 } else {
1352 eval qq/print "\\t$var;\\n"/;
1353 warn $@ if $@;
1354 $init =~ s/^;//;
1355 }
1356 $deferred .= eval qq/"\\n\\t$init\\n"/;
1357 warn $@ if $@;
1358 }
93a17b20 1359}
1360
c2960299 1361sub Warn
1362{
1363 # work out the line number
1364 my $line_no = $line_no[@line_no - @line -1] ;
1365
1366 print STDERR "@_ in $filename, line $line_no\n" ;
1367}
1368
1369sub blurt
1370{
1371 Warn @_ ;
1372 $errors ++
1373}
1374
1375sub death
1376{
1377 Warn @_ ;
1378 exit 1 ;
1379}
8990e307 1380
93a17b20 1381sub generate_init {
2304df62 1382 local($type, $num, $var) = @_;
a0d0e21e 1383 local($arg) = "ST(" . ($num - 1) . ")";
2304df62 1384 local($argoff) = $num - 1;
1385 local($ntype);
1386 local($tk);
93a17b20 1387
f06db76b 1388 $type = TidyType($type) ;
c2960299 1389 blurt("Error: '$type' not in typemap"), return
1390 unless defined($type_kind{$type});
1391
2304df62 1392 ($ntype = $type) =~ s/\s*\*/Ptr/g;
8e07c86e 1393 ($subtype = $ntype) =~ s/(?:Array)?(?:Ptr)?$//;
2304df62 1394 $tk = $type_kind{$type};
1395 $tk =~ s/OBJ$/REF/ if $func_name =~ /DESTROY$/;
8e07c86e 1396 $type =~ tr/:/_/;
c2960299 1397 blurt("Error: No INPUT definition for type '$type' found"), return
1398 unless defined $input_expr{$tk} ;
2304df62 1399 $expr = $input_expr{$tk};
1400 if ($expr =~ /DO_ARRAY_ELEM/) {
c2960299 1401 blurt("Error: '$subtype' not in typemap"), return
1402 unless defined($type_kind{$subtype});
1403 blurt("Error: No INPUT definition for type '$subtype' found"), return
1404 unless defined $input_expr{$type_kind{$subtype}} ;
2304df62 1405 $subexpr = $input_expr{$type_kind{$subtype}};
1406 $subexpr =~ s/ntype/subtype/g;
1407 $subexpr =~ s/\$arg/ST(ix_$var)/g;
1408 $subexpr =~ s/\n\t/\n\t\t/g;
93d3b392 1409 $subexpr =~ s/is not of (.*\")/[arg %d] is not of $1, ix_$var + 1/g;
a0d0e21e 1410 $subexpr =~ s/\$var/${var}[ix_$var - $argoff]/;
2304df62 1411 $expr =~ s/DO_ARRAY_ELEM/$subexpr/;
1412 }
db3b9414 1413 if ($expr =~ m#/\*.*scope.*\*/#i) { # "scope" in C comments
1414 $ScopeThisXSUB = 1;
1415 }
2304df62 1416 if (defined($defaults{$var})) {
1417 $expr =~ s/(\t+)/$1 /g;
1418 $expr =~ s/ /\t/g;
1419 eval qq/print "\\t$var;\\n"/;
7ad6fb0b 1420 warn $@ if $@;
2304df62 1421 $deferred .= eval qq/"\\n\\tif (items < $num)\\n\\t $var = $defaults{$var};\\n\\telse {\\n$expr;\\n\\t}\\n"/;
7ad6fb0b 1422 warn $@ if $@;
db3b9414 1423 } elsif ($ScopeThisXSUB or $expr !~ /^\t\$var =/) {
2304df62 1424 eval qq/print "\\t$var;\\n"/;
7ad6fb0b 1425 warn $@ if $@;
2304df62 1426 $deferred .= eval qq/"\\n$expr;\\n"/;
7ad6fb0b 1427 warn $@ if $@;
2304df62 1428 } else {
1429 eval qq/print "$expr;\\n"/;
7ad6fb0b 1430 warn $@ if $@;
2304df62 1431 }
93a17b20 1432}
1433
1434sub generate_output {
ef50df4b 1435 local($type, $num, $var, $do_setmagic) = @_;
a0d0e21e 1436 local($arg) = "ST(" . ($num - ($num != 0)) . ")";
2304df62 1437 local($argoff) = $num - 1;
1438 local($ntype);
93a17b20 1439
f06db76b 1440 $type = TidyType($type) ;
2304df62 1441 if ($type =~ /^array\(([^,]*),(.*)\)/) {
1442 print "\tsv_setpvn($arg, (char *)$var, $2 * sizeof($1)), XFree((char *)$var);\n";
ef50df4b 1443 print "\tSvSETMAGIC($arg);\n" if $do_setmagic;
2304df62 1444 } else {
f06db76b 1445 blurt("Error: '$type' not in typemap"), return
2304df62 1446 unless defined($type_kind{$type});
c2960299 1447 blurt("Error: No OUTPUT definition for type '$type' found"), return
1448 unless defined $output_expr{$type_kind{$type}} ;
2304df62 1449 ($ntype = $type) =~ s/\s*\*/Ptr/g;
1450 $ntype =~ s/\(\)//g;
8e07c86e 1451 ($subtype = $ntype) =~ s/(?:Array)?(?:Ptr)?$//;
2304df62 1452 $expr = $output_expr{$type_kind{$type}};
1453 if ($expr =~ /DO_ARRAY_ELEM/) {
c2960299 1454 blurt("Error: '$subtype' not in typemap"), return
1455 unless defined($type_kind{$subtype});
1456 blurt("Error: No OUTPUT definition for type '$subtype' found"), return
1457 unless defined $output_expr{$type_kind{$subtype}} ;
2304df62 1458 $subexpr = $output_expr{$type_kind{$subtype}};
1459 $subexpr =~ s/ntype/subtype/g;
1460 $subexpr =~ s/\$arg/ST(ix_$var)/g;
1461 $subexpr =~ s/\$var/${var}[ix_$var]/g;
1462 $subexpr =~ s/\n\t/\n\t\t/g;
1463 $expr =~ s/DO_ARRAY_ELEM\n/$subexpr/;
a0d0e21e 1464 eval "print qq\a$expr\a";
7ad6fb0b 1465 warn $@ if $@;
ef50df4b 1466 print "\t\tSvSETMAGIC(ST(ix_$var));\n" if $do_setmagic;
2304df62 1467 }
a0d0e21e 1468 elsif ($var eq 'RETVAL') {
a2baab1c 1469 if ($expr =~ /^\t\$arg = new/) {
1470 # We expect that $arg has refcnt 1, so we need to
1471 # mortalize it.
a0d0e21e 1472 eval "print qq\a$expr\a";
7ad6fb0b 1473 warn $@ if $@;
2304df62 1474 print "\tsv_2mortal(ST(0));\n";
ef50df4b 1475 print "\tSvSETMAGIC(ST(0));\n" if $do_setmagic;
93a17b20 1476 }
a2baab1c 1477 elsif ($expr =~ /^\s*\$arg\s*=/) {
1478 # We expect that $arg has refcnt >=1, so we need
d689ffdd 1479 # to mortalize it!
a2baab1c 1480 eval "print qq\a$expr\a";
7ad6fb0b 1481 warn $@ if $@;
d689ffdd 1482 print "\tsv_2mortal(ST(0));\n";
ef50df4b 1483 print "\tSvSETMAGIC(ST(0));\n" if $do_setmagic;
a2baab1c 1484 }
2304df62 1485 else {
a2baab1c 1486 # Just hope that the entry would safely write it
1487 # over an already mortalized value. By
1488 # coincidence, something like $arg = &sv_undef
1489 # works too.
8990e307 1490 print "\tST(0) = sv_newmortal();\n";
a0d0e21e 1491 eval "print qq\a$expr\a";
7ad6fb0b 1492 warn $@ if $@;
ef50df4b 1493 # new mortals don't have set magic
463ee0b2 1494 }
2304df62 1495 }
a0d0e21e 1496 elsif ($arg =~ /^ST\(\d+\)$/) {
1497 eval "print qq\a$expr\a";
7ad6fb0b 1498 warn $@ if $@;
ef50df4b 1499 print "\tSvSETMAGIC($arg);\n" if $do_setmagic;
a0d0e21e 1500 }
2304df62 1501 }
93a17b20 1502}
1503
1504sub map_type {
e50aee73 1505 my($type) = @_;
93a17b20 1506
8e07c86e 1507 $type =~ tr/:/_/;
1508 $type =~ s/^array\(([^,]*),(.*)\).*/$1 */s;
1509 $type;
93a17b20 1510}
8990e307 1511
e50aee73 1512
1513sub Exit {
ff0cee69 1514# If this is VMS, the exit status has meaning to the shell, so we
1515# use a predictable value (SS$_Normal or SS$_Abort) rather than an
1516# arbitrary number.
1517# exit ($Is_VMS ? ($errors ? 44 : 1) : $errors) ;
1518 exit ($errors ? 1 : 0);
e50aee73 1519}