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