Updated from xsubpp-1.924 to 1.929.
[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), perlapi(1)
75
76 =cut
77
78 # Global Constants
79 $XSUBPP_version = "1.929";
80 require 5.002;
81
82 sub Q ;
83
84 $FH_string = 'File0000' ;
85 *FH = $FH_string ;
86
87 $usage = "Usage: xsubpp [-v] [-C++] [-except] [-prototypes] [-noversioncheck] [-s pattern] [-typemap typemap]... file.xs\n";
88
89 $proto_re = "[" . quotemeta('\$%&*@;') . "]" ;
90
91 $except = "";
92 $WantPrototypes = -1 ;
93 $WantVersionChk = 1 ;
94 $ProtoUsed = 0 ;
95 SWITCH: while (@ARGV and $ARGV[0] =~ /^-./) {
96     $flag = shift @ARGV;
97     $flag =~ s/^-// ;
98     $spat = shift,      next SWITCH     if $flag eq 's';
99     $cplusplus = 1,     next SWITCH     if $flag eq 'C++';
100     $WantPrototypes = 0, next SWITCH    if $flag eq 'noprototypes';
101     $WantPrototypes = 1, next SWITCH    if $flag eq 'prototypes';
102     $WantVersionChk = 0, next SWITCH    if $flag eq 'noversioncheck';
103     $WantVersionChk = 1, next SWITCH    if $flag eq 'versioncheck';
104     $except = " TRY",   next SWITCH     if $flag eq 'except';
105     push(@tm,shift),    next SWITCH     if $flag eq 'typemap';
106     (print "xsubpp version $XSUBPP_version\n"), exit    
107         if $flag eq 'v';
108     die $usage;
109 }
110 if ($WantPrototypes == -1)
111   { $WantPrototypes = 0}
112 else
113   { $ProtoUsed = 1 }
114
115
116 @ARGV == 1 or die $usage;
117 ($dir, $filename) = $ARGV[0] =~ m#(.*)/(.*)#
118         or ($dir, $filename) = $ARGV[0] =~ m#(.*[>\]])(.*)#
119         or ($dir, $filename) = ('.', $ARGV[0]);
120 chdir($dir);
121 # Check for VMS; Config.pm may not be installed yet, but this routine
122 # is built into VMS perl
123 if (defined(&VMS::Filespec::vmsify)) { $Is_VMS = 1; $pwd = $ENV{DEFAULT}; }
124 else                                 { $Is_VMS = 0; chomp($pwd = `pwd`);   }
125
126 ++ $IncludedFiles{$ARGV[0]} ;
127
128 sub TrimWhitespace
129 {
130     $_[0] =~ s/^\s+|\s+$//go ;
131 }
132
133 sub TidyType
134 {
135     local ($_) = @_ ;
136
137     # rationalise any '*' by joining them into bunches and removing whitespace
138     s#\s*(\*+)\s*#$1#g;
139     s#(\*+)# $1 #g ;
140
141     # change multiple whitespace into a single space
142     s/\s+/ /g ;
143     
144     # trim leading & trailing whitespace
145     TrimWhitespace($_) ;
146
147     $_ ;
148 }
149
150 $typemap = shift @ARGV;
151 foreach $typemap (@tm) {
152     die "Can't find $typemap in $pwd\n" unless -r $typemap;
153 }
154 unshift @tm, qw(../../../../lib/ExtUtils/typemap ../../../lib/ExtUtils/typemap
155                 ../../lib/ExtUtils/typemap ../../../typemap ../../typemap
156                 ../typemap typemap);
157 foreach $typemap (@tm) {
158     next unless -e $typemap ;
159     # skip directories, binary files etc.
160     warn("Warning: ignoring non-text typemap file '$typemap'\n"), next 
161         unless -T $typemap ;
162     open(TYPEMAP, $typemap) 
163         or warn ("Warning: could not open typemap file '$typemap': $!\n"), next;
164     $mode = 'Typemap';
165     $junk = "" ;
166     $current = \$junk;
167     while (<TYPEMAP>) {
168         next if /^\s*#/;
169         if (/^INPUT\s*$/)   { $mode = 'Input';   $current = \$junk;  next; }
170         if (/^OUTPUT\s*$/)  { $mode = 'Output';  $current = \$junk;  next; }
171         if (/^TYPEMAP\s*$/) { $mode = 'Typemap'; $current = \$junk;  next; }
172         if ($mode eq 'Typemap') {
173             chomp;
174             my $line = $_ ;
175             TrimWhitespace($_) ;
176             # skip blank lines and comment lines
177             next if /^$/ or /^#/ ;
178             my($type,$kind, $proto) = /^\s*(.*?\S)\s+(\S+)\s*($proto_re*)\s*$/ or
179                 warn("Warning: File '$typemap' Line $. '$line' TYPEMAP entry needs 2 or 3 columns\n"), next;
180             $type = TidyType($type) ;
181             $type_kind{$type} = $kind ;
182             # prototype defaults to '$'
183             $proto = '$' unless $proto ;
184             warn("Warning: File '$typemap' Line $. '$line' Invalid prototype '$proto'\n") 
185                 unless ValidProtoString($proto) ;
186             $proto_letter{$type} = C_string($proto) ;
187         }
188         elsif (/^\s/) {
189             $$current .= $_;
190         }
191         elsif ($mode eq 'Input') {
192             s/\s+$//;
193             $input_expr{$_} = '';
194             $current = \$input_expr{$_};
195         }
196         else {
197             s/\s+$//;
198             $output_expr{$_} = '';
199             $current = \$output_expr{$_};
200         }
201     }
202     close(TYPEMAP);
203 }
204
205 foreach $key (keys %input_expr) {
206     $input_expr{$key} =~ s/\n+$//;
207 }
208
209 $END = "!End!\n\n";             # "impossible" keyword (multiple newline)
210
211 # Match an XS keyword
212 $BLOCK_re= '\s*(' . join('|', qw(
213         REQUIRE BOOT CASE PREINIT INPUT INIT CODE PPCODE OUTPUT 
214         CLEANUP ALIAS PROTOTYPES PROTOTYPE VERSIONCHECK INCLUDE
215         )) . "|$END)\\s*:";
216
217 # Input:  ($_, @line) == unparsed input.
218 # Output: ($_, @line) == (rest of line, following lines).
219 # Return: the matched keyword if found, otherwise 0
220 sub check_keyword {
221         $_ = shift(@line) while !/\S/ && @line;
222         s/^(\s*)($_[0])\s*:\s*(?:#.*)?/$1/s && $2;
223 }
224
225
226 sub print_section {
227     $_ = shift(@line) while !/\S/ && @line;
228     for (;  defined($_) && !/^$BLOCK_re/o;  $_ = shift(@line)) {
229         print "$_\n";
230     }
231 }
232
233 sub process_keyword($)
234 {
235     my($pattern) = @_ ;
236     my $kwd ;
237
238     &{"${kwd}_handler"}() 
239         while $kwd = check_keyword($pattern) ;
240 }
241
242 sub CASE_handler {
243     blurt ("Error: `CASE:' after unconditional `CASE:'")
244         if $condnum && $cond eq '';
245     $cond = $_;
246     TrimWhitespace($cond);
247     print "   ", ($condnum++ ? " else" : ""), ($cond ? " if ($cond)\n" : "\n");
248     $_ = '' ;
249 }
250
251 sub INPUT_handler {
252     for (;  !/^$BLOCK_re/o;  $_ = shift(@line)) {
253         last if /^\s*NOT_IMPLEMENTED_YET/;
254         next unless /\S/;       # skip blank lines 
255
256         TrimWhitespace($_) ;
257         my $line = $_ ;
258
259         # remove trailing semicolon if no initialisation
260         s/\s*;$//g unless /=/ ;
261
262         # check for optional initialisation code
263         my $var_init = '' ;
264         $var_init = $1 if s/\s*(=.*)$//s ;
265         $var_init =~ s/"/\\"/g;
266
267         s/\s+/ /g;
268         my ($var_type, $var_addr, $var_name) = /^(.*?[^& ]) *(\&?) *\b(\w+)$/s
269             or blurt("Error: invalid argument declaration '$line'"), next;
270
271         # Check for duplicate definitions
272         blurt ("Error: duplicate definition of argument '$var_name' ignored"), next
273             if $arg_list{$var_name} ++  ;
274
275         $thisdone |= $var_name eq "THIS";
276         $retvaldone |= $var_name eq "RETVAL";
277         $var_types{$var_name} = $var_type;
278         print "\t" . &map_type($var_type);
279         $var_num = $args_match{$var_name};
280
281         $proto_arg[$var_num] = ProtoString($var_type) 
282             if $var_num ;
283         if ($var_addr) {
284             $var_addr{$var_name} = 1;
285             $func_args =~ s/\b($var_name)\b/&$1/;
286         }
287         if ($var_init =~ /^=\s*NO_INIT\s*;?\s*$/) {
288             print "\t$var_name;\n";
289         } elsif ($var_init =~ /\S/) {
290             &output_init($var_type, $var_num, "$var_name $var_init");
291         } elsif ($var_num) {
292             # generate initialization code
293             &generate_init($var_type, $var_num, $var_name);
294         } else {
295             print ";\n";
296         }
297     }
298 }
299
300 sub OUTPUT_handler {
301     for (;  !/^$BLOCK_re/o;  $_ = shift(@line)) {
302         next unless /\S/;
303         my ($outarg, $outcode) = /^\s*(\S+)\s*(.*?)\s*$/s ;
304         blurt ("Error: duplicate OUTPUT argument '$outarg' ignored"), next
305             if $outargs{$outarg} ++ ;
306         if (!$gotRETVAL and $outarg eq 'RETVAL') {
307             # deal with RETVAL last
308             $RETVAL_code = $outcode ;
309             $gotRETVAL = 1 ;
310             next ;
311         }
312         blurt ("Error: OUTPUT $outarg not an argument"), next
313             unless defined($args_match{$outarg});
314         blurt("Error: No input definition for OUTPUT argument '$outarg' - ignored"), next
315             unless defined $var_types{$outarg} ;
316         if ($outcode) {
317             print "\t$outcode\n";
318         } else {
319             $var_num = $args_match{$outarg};
320             &generate_output($var_types{$outarg}, $var_num, $outarg); 
321         }
322     }
323 }
324
325 sub CLEANUP_handler() { print_section() } 
326 sub PREINIT_handler() { print_section() } 
327 sub INIT_handler()    { print_section() } 
328
329 sub GetAliases
330 {
331     my ($line) = @_ ;
332     my ($orig) = $line ;
333     my ($alias) ;
334     my ($value) ;
335
336     # Parse alias definitions
337     # format is
338     #    alias = value alias = value ...
339
340     while ($line =~ s/^\s*([\w:]+)\s*=\s*(\w+)\s*//) {
341         $alias = $1 ;
342         $orig_alias = $alias ;
343         $value = $2 ;
344
345         # check for optional package definition in the alias
346         $alias = $Packprefix . $alias if $alias !~ /::/ ;
347         
348         # check for duplicate alias name & duplicate value
349         Warn("Warning: Ignoring duplicate alias '$orig_alias'")
350             if defined $XsubAliases{$pname}{$alias} ;
351
352         Warn("Warning: Aliases '$orig_alias' and '$XsubAliasValues{$pname}{$value}' have identical values")
353             if $XsubAliasValues{$pname}{$value} ;
354
355         $XsubAliases{$pname}{$alias} = $value ;
356         $XsubAliasValues{$pname}{$value} = $orig_alias ;
357     }
358
359     blurt("Error: Cannot parse ALIAS definitions from '$orig'")
360         if $line ;
361 }
362
363 sub ALIAS_handler ()
364 {
365     for (;  !/^$BLOCK_re/o;  $_ = shift(@line)) {
366         next unless /\S/;
367         TrimWhitespace($_) ;
368         GetAliases($_) if $_ ;
369     }
370 }
371
372 sub REQUIRE_handler ()
373 {
374     # the rest of the current line should contain a version number
375     my ($Ver) = $_ ;
376
377     TrimWhitespace($Ver) ;
378
379     death ("Error: REQUIRE expects a version number")
380         unless $Ver ;
381
382     # check that the version number is of the form n.n
383     death ("Error: REQUIRE: expected a number, got '$Ver'")
384         unless $Ver =~ /^\d+(\.\d*)?/ ;
385
386     death ("Error: xsubpp $Ver (or better) required--this is only $XSUBPP_version.")
387         unless $XSUBPP_version >= $Ver ; 
388 }
389
390 sub VERSIONCHECK_handler ()
391 {
392     # the rest of the current line should contain either ENABLE or
393     # DISABLE
394  
395     TrimWhitespace($_) ;
396  
397     # check for ENABLE/DISABLE
398     death ("Error: VERSIONCHECK: ENABLE/DISABLE")
399         unless /^(ENABLE|DISABLE)/i ;
400  
401     $WantVersionChk = 1 if $1 eq 'ENABLE' ;
402     $WantVersionChk = 0 if $1 eq 'DISABLE' ;
403  
404 }
405
406 sub PROTOTYPE_handler ()
407 {
408     for (;  !/^$BLOCK_re/o;  $_ = shift(@line)) {
409         next unless /\S/;
410         TrimWhitespace($_) ;
411         if ($_ eq 'DISABLE') {
412            $ProtoThisXSUB = 0 
413         }
414         elsif ($_ eq 'ENABLE') {
415            $ProtoThisXSUB = 1 
416         }
417         else {
418             # remove any whitespace
419             s/\s+//g ;
420             death("Error: Invalid prototype '$_'")
421                 unless ValidProtoString($_) ;
422             $ProtoThisXSUB = C_string($_) ;
423         }
424     }
425     $ProtoUsed = 1 ;
426 }
427
428 sub PROTOTYPES_handler ()
429 {
430     # the rest of the current line should contain either ENABLE or
431     # DISABLE 
432
433     TrimWhitespace($_) ;
434
435     # check for ENABLE/DISABLE
436     death ("Error: PROTOTYPES: ENABLE/DISABLE")
437         unless /^(ENABLE|DISABLE)/i ;
438
439     $WantPrototypes = 1 if $1 eq 'ENABLE' ;
440     $WantPrototypes = 0 if $1 eq 'DISABLE' ;
441     $ProtoUsed = 1 ;
442
443 }
444
445 sub INCLUDE_handler ()
446 {
447     # the rest of the current line should contain a valid filename
448  
449     TrimWhitespace($_) ;
450  
451     # If the filename is enclosed in quotes, remove them.
452     s/^'([^']*)'$/$1/ or s/^"([^"]*)"$/$1/ ;
453
454     death("INCLUDE: filename missing")
455         unless $_ ;
456
457     death("INCLUDE: output pipe is illegal")
458         if /^\s*\|/ ;
459
460     # simple minded recursion detector
461     death("INCLUDE loop detected")
462         if $IncludedFiles{$_} ;
463
464     ++ $IncludedFiles{$_} unless /\|\s*$/ ;
465
466     # Save the current file context.
467     push(@FileStack, {
468         LastLine        => $lastline,
469         LastLineNo      => $lastline_no,
470         Line            => \@line,
471         LineNo          => \@line_no,
472         Filename        => $filename,
473         Handle          => $FH_string,
474         }) ;
475  
476     ++ $FH_string ;
477
478     # open the new file
479     open ($FH_string, "$_") or death("Cannot open '$_': $!") ;
480  
481     print Q<<"EOF" ;
482 #
483 #/* INCLUDE:  Including '$_' from '$filename' */
484 #
485 EOF
486
487     *FH = $FH_string ;
488     $filename = $_ ;
489
490     # Prime the pump by reading the first line
491     $lastline = <FH> ;
492     $lastline_no = $. ;
493  
494 }
495  
496 sub PopFile()
497 {
498     return 0 unless @FileStack ;
499  
500     my $data     = pop @FileStack ;
501     my $ThisFile = $filename ;
502     my $isPipe   = ($filename =~ /\|\s*$/) ;
503  
504     -- $IncludedFiles{$filename}
505         unless $isPipe ;
506
507     close FH ;
508
509     *FH         = $data->{Handle} ;
510     $filename   = $data->{Filename} ;
511     $lastline   = $data->{LastLine} ;
512     $lastline_no = $data->{LastLineNo} ;
513     @line       = @{ $data->{Line} } ;
514     @line_no    = @{ $data->{LineNo} } ;
515  
516     if ($isPipe and $? ) {
517         -- $lastline_no ;
518         print STDERR "Error reading from pipe '$ThisFile': $! in $filename, line $lastline_no\n"  ;
519         exit 1 ;
520     }
521
522     print Q<<"EOF" ;
523 #
524 #/* INCLUDE: Returning to '$filename' from '$ThisFile' */
525 #
526 EOF
527
528     return 1 ;
529 }
530
531 sub ValidProtoString ($)
532 {
533     my($string) = @_ ;
534
535     if ( $string =~ /^$proto_re+$/ ) {
536         return $string ;
537     }
538
539     return 0 ;
540 }
541
542 sub C_string ($)
543 {
544     my($string) = @_ ;
545
546     $string =~ s[\\][\\\\]g ;
547     $string ;
548 }
549
550 sub ProtoString ($)
551 {
552     my ($type) = @_ ;
553
554     $proto_letter{$type} or '$' ;
555 }
556
557 sub check_cpp {
558     my @cpp = grep(/^\#\s*(?:if|e\w+)/, @line);
559     if (@cpp) {
560         my ($cpp, $cpplevel);
561         for $cpp (@cpp) {
562             if ($cpp =~ /^\#\s*if/) {
563                 $cpplevel++;
564             } elsif (!$cpplevel) {
565                 Warn("Warning: #else/elif/endif without #if in this function");
566                 return;
567             } elsif ($cpp =~ /^\#\s*endif/) {
568                 $cpplevel--;
569             }
570         }
571         Warn("Warning: #if without #endif in this function") if $cpplevel;
572     }
573 }
574
575
576 sub Q {
577     my($text) = @_;
578     $text =~ s/^#//gm;
579     $text =~ s/\[\[/{/g;
580     $text =~ s/\]\]/}/g;
581     $text;
582 }
583
584 open(FH, $filename) or die "cannot open $filename: $!\n";
585
586 # Identify the version of xsubpp used
587 print <<EOM ;
588 /*
589  * This file was generated automatically by xsubpp version $XSUBPP_version from the 
590  * contents of $filename. Don't edit this file, edit $filename instead.
591  *
592  *      ANY CHANGES MADE HERE WILL BE LOST! 
593  *
594  */
595
596 EOM
597  
598
599 while (<FH>) {
600     last if ($Module, $Package, $Prefix) =
601         /^MODULE\s*=\s*([\w:]+)(?:\s+PACKAGE\s*=\s*([\w:]+))?(?:\s+PREFIX\s*=\s*(\S+))?\s*$/;
602     print $_;
603 }
604 &Exit unless defined $_;
605
606 $lastline    = $_;
607 $lastline_no = $.;
608
609
610 # Read next xsub into @line from ($lastline, <FH>).
611 sub fetch_para {
612     # parse paragraph
613     @line = ();
614     @line_no = () ;
615     if (! defined $lastline) {
616         return 1 if PopFile() ;
617         return 0 ; 
618     }
619
620     if ($lastline =~
621         /^MODULE\s*=\s*([\w:]+)(?:\s+PACKAGE\s*=\s*([\w:]+))?(?:\s+PREFIX\s*=\s*(\S+))?\s*$/) {
622         $Module = $1;
623         $Package = defined($2) ? $2 : '';       # keep -w happy
624         $Prefix  = defined($3) ? $3 : '';       # keep -w happy
625         ($Module_cname = $Module) =~ s/\W/_/g;
626         ($Packid = $Package) =~ tr/:/_/;
627         $Packprefix = $Package;
628         $Packprefix .= "::" if $Packprefix ne "";
629         $lastline = "";
630     }
631
632     for(;;) {
633         if ($lastline !~ /^\s*#/ ||
634             $lastline =~ /^#[ \t]*(?:(?:if|ifn?def|else|elif|endif|define|undef|pragma)\b|include\s*["<].*[>"])/) {
635             last if $lastline =~ /^\S/ && @line && $line[-1] eq "";
636             push(@line, $lastline);
637             push(@line_no, $lastline_no) ;
638         }
639
640         # Read next line and continuation lines
641         last unless defined($lastline = <FH>);
642         $lastline_no = $.;
643         my $tmp_line;
644         $lastline .= $tmp_line
645             while ($lastline =~ /\\$/ && defined($tmp_line = <FH>));
646             
647         chomp $lastline;
648         $lastline =~ s/^\s+$//;
649     }
650     pop(@line), pop(@line_no) while @line && $line[-1] eq "";
651     1;
652 }
653
654 PARAGRAPH:
655 while (fetch_para()) {
656     # Print initial preprocessor statements and blank lines
657     print shift(@line), "\n"
658         while @line && $line[0] !~ /^[^\#]/;
659
660     next PARAGRAPH unless @line;
661
662     death ("Code is not inside a function")
663         if $line[0] =~ /^\s/;
664
665     # initialize info arrays
666     undef(%args_match);
667     undef(%var_types);
668     undef(%var_addr);
669     undef(%defaults);
670     undef($class);
671     undef($static);
672     undef($elipsis);
673     undef($wantRETVAL) ;
674     undef(%arg_list) ;
675     undef(@proto_arg) ;
676     $ProtoThisXSUB = $WantPrototypes ;
677
678     $_ = shift(@line);
679     while ($kwd = check_keyword("REQUIRE|PROTOTYPES|VERSIONCHECK|INCLUDE")) {
680         &{"${kwd}_handler"}() ;
681         next PARAGRAPH unless @line ;
682         $_ = shift(@line);
683     }
684
685     if (check_keyword("BOOT")) {
686         &check_cpp;
687         push (@BootCode, $_, @line, "") ;
688         next PARAGRAPH ;
689     }
690
691
692     # extract return type, function name and arguments
693     my($ret_type) = TidyType($_);
694
695     # a function definition needs at least 2 lines
696     blurt ("Error: Function definition too short '$ret_type'"), next PARAGRAPH
697         unless @line ;
698
699     $static = 1 if $ret_type =~ s/^static\s+//;
700
701     $func_header = shift(@line);
702     blurt ("Error: Cannot parse function definition from '$func_header'"), next PARAGRAPH
703         unless $func_header =~ /^(?:([\w:]*)::)?(\w+)\s*\(\s*(.*?)\s*\)\s*$/s;
704
705     ($class, $func_name, $orig_args) =  ($1, $2, $3) ;
706     ($pname = $func_name) =~ s/^($Prefix)?/$Packprefix/;
707
708     # Check for duplicate function definition
709     if (defined $Func_name{"${Packid}_$func_name"} ) {
710        Warn("Warning: duplicate function definition '$func_name' detected") 
711     }
712     else {
713         push(@Func_name, "${Packid}_$func_name");
714         push(@Func_pname, $pname);
715     }
716     $Func_name{"${Packid}_$func_name"} ++ ;
717
718     @args = split(/\s*,\s*/, $orig_args);
719     if (defined($class)) {
720         my $arg0 = ((defined($static) or $func_name =~ /^new/) ? "CLASS" : "THIS");
721         unshift(@args, $arg0);
722         ($orig_args = "$arg0, $orig_args") =~ s/^$arg0, $/$arg0/;
723     }
724     $orig_args =~ s/"/\\"/g;
725     $min_args = $num_args = @args;
726     foreach $i (0..$num_args-1) {
727             if ($args[$i] =~ s/\.\.\.//) {
728                     $elipsis = 1;
729                     $min_args--;
730                     if ($args[$i] eq '' && $i == $num_args - 1) {
731                         pop(@args);
732                         last;
733                     }
734             }
735             if ($args[$i] =~ /^([^=]*[^\s=])\s*=\s*(.*)/s) {
736                     $min_args--;
737                     $args[$i] = $1;
738                     $defaults{$args[$i]} = $2;
739                     $defaults{$args[$i]} =~ s/"/\\"/g;
740             }
741             $proto_arg[$i+1] = '$' ;
742     }
743     if (defined($class)) {
744             $func_args = join(", ", @args[1..$#args]);
745     } else {
746             $func_args = join(", ", @args);
747     }
748     @args_match{@args} = 1..@args;
749
750     $PPCODE = grep(/^\s*PPCODE\s*:/, @line);
751     $ALIAS  = grep(/^\s*ALIAS\s*:/,  @line);
752
753     # print function header
754     print Q<<"EOF";
755 #XS(XS_${Packid}_$func_name)
756 #[[
757 #    dXSARGS;
758 EOF
759     print Q<<"EOF" if $ALIAS ;
760 #    dXSI32;
761 EOF
762     if ($elipsis) {
763         $cond = ($min_args ? qq(items < $min_args) : 0);
764     }
765     elsif ($min_args == $num_args) {
766         $cond = qq(items != $min_args);
767     }
768     else {
769         $cond = qq(items < $min_args || items > $num_args);
770     }
771
772     print Q<<"EOF" if $except;
773 #    char errbuf[1024];
774 #    *errbuf = '\0';
775 EOF
776
777     if ($ALIAS) 
778       { print Q<<"EOF" if $cond }
779 #    if ($cond)
780 #       croak("Usage: %s($orig_args)", GvNAME(CvGV(cv)));
781 EOF
782     else 
783       { print Q<<"EOF" if $cond }
784 #    if ($cond)
785 #       croak("Usage: $pname($orig_args)");
786 EOF
787
788     print Q<<"EOF" if $PPCODE;
789 #    SP -= items;
790 EOF
791
792     # Now do a block of some sort.
793
794     $condnum = 0;
795     $cond = '';                 # last CASE: condidional
796     push(@line, "$END:");
797     push(@line_no, $line_no[-1]);
798     $_ = '';
799     &check_cpp;
800     while (@line) {
801         &CASE_handler if check_keyword("CASE");
802         print Q<<"EOF";
803 #   $except [[
804 EOF
805
806         # do initialization of input variables
807         $thisdone = 0;
808         $retvaldone = 0;
809         $deferred = "";
810         %arg_list = () ;
811         $gotRETVAL = 0;
812
813         INPUT_handler() ;
814         process_keyword("INPUT|PREINIT|ALIAS|PROTOTYPE") ;
815
816         if (!$thisdone && defined($class)) {
817             if (defined($static) or $func_name =~ /^new/) {
818                 print "\tchar *";
819                 $var_types{"CLASS"} = "char *";
820                 &generate_init("char *", 1, "CLASS");
821             }
822             else {
823                 print "\t$class *";
824                 $var_types{"THIS"} = "$class *";
825                 &generate_init("$class *", 1, "THIS");
826             }
827         }
828
829         # do code
830         if (/^\s*NOT_IMPLEMENTED_YET/) {
831                 print "\n\tcroak(\"$pname: not implemented yet\");\n";
832                 $_ = '' ;
833         } else {
834                 if ($ret_type ne "void") {
835                         print "\t" . &map_type($ret_type) . "\tRETVAL;\n"
836                                 if !$retvaldone;
837                         $args_match{"RETVAL"} = 0;
838                         $var_types{"RETVAL"} = $ret_type;
839                 }
840                 print $deferred;
841                 process_keyword("INIT|ALIAS|PROTOTYPE") ;
842
843                 if (check_keyword("PPCODE")) {
844                         print_section();
845                         death ("PPCODE must be last thing") if @line;
846                         print "\tPUTBACK;\n\treturn;\n";
847                 } elsif (check_keyword("CODE")) {
848                         print_section() ;
849                 } elsif (defined($class) and $func_name eq "DESTROY") {
850                         print "\n\t";
851                         print "delete THIS;\n";
852                 } else {
853                         print "\n\t";
854                         if ($ret_type ne "void") {
855                                 print "RETVAL = ";
856                                 $wantRETVAL = 1;
857                         }
858                         if (defined($static)) {
859                             if ($func_name =~ /^new/) {
860                                 $func_name = "$class";
861                             } else {
862                                 print "${class}::";
863                             }
864                         } elsif (defined($class)) {
865                             if ($func_name =~ /^new/) {
866                                 $func_name .= " $class";
867                             } else {
868                                 print "THIS->";
869                             }
870                         }
871                         $func_name =~ s/^($spat)//
872                             if defined($spat);
873                         print "$func_name($func_args);\n";
874                 }
875         }
876
877         # do output variables
878         $gotRETVAL = 0;
879         undef $RETVAL_code ;
880         undef %outargs ;
881         process_keyword("OUTPUT|ALIAS|PROTOTYPE"); 
882
883         # all OUTPUT done, so now push the return value on the stack
884         if ($gotRETVAL && $RETVAL_code) {
885             print "\t$RETVAL_code\n";
886         } elsif ($gotRETVAL || $wantRETVAL) {
887             &generate_output($ret_type, 0, 'RETVAL');
888         }
889
890         # do cleanup
891         process_keyword("CLEANUP|ALIAS|PROTOTYPE") ;
892
893         # print function trailer
894         print Q<<EOF;
895 #    ]]
896 EOF
897         print Q<<EOF if $except;
898 #    BEGHANDLERS
899 #    CATCHALL
900 #       sprintf(errbuf, "%s: %s\\tpropagated", Xname, Xreason);
901 #    ENDHANDLERS
902 EOF
903         if (check_keyword("CASE")) {
904             blurt ("Error: No `CASE:' at top of function")
905                 unless $condnum;
906             $_ = "CASE: $_";    # Restore CASE: label
907             next;
908         }
909         last if $_ eq "$END:";
910         death(/^$BLOCK_re/o ? "Misplaced `$1:'" : "Junk at end of function");
911     }
912
913     print Q<<EOF if $except;
914 #    if (errbuf[0])
915 #       croak(errbuf);
916 EOF
917
918     print Q<<EOF unless $PPCODE;
919 #    XSRETURN(1);
920 EOF
921
922     print Q<<EOF;
923 #]]
924 #
925 EOF
926
927     # Build the prototype string for the xsub
928     if ($ProtoThisXSUB) {
929         if ($ProtoThisXSUB != 1) {
930             $ProtoXSUB{$pname} = '"' . $ProtoThisXSUB . '"'
931         }
932         else {
933             my $s = ';';
934             if ($min_args < $num_args)  {
935                 $s = ''; 
936                 $proto_arg[$min_args] .= ";" ;
937             }
938             push @proto_arg, "${s}@" 
939                 if $elipsis ;
940     
941             $ProtoXSUB{$pname} = '"' . join ("", @proto_arg) . '"' 
942         }
943     }
944
945 }
946
947 # print initialization routine
948 print Q<<"EOF";
949 ##ifdef __cplusplus
950 #extern "C"
951 ##endif
952 #XS(boot_$Module_cname)
953 #[[
954 #    dXSARGS;
955 #    char* file = __FILE__;
956 #
957 EOF
958
959 print Q<<"EOF" if $WantVersionChk ;
960 #    XS_VERSION_BOOTCHECK ;
961 #
962 EOF
963
964 print Q<<"EOF" if defined %XsubAliases ;
965 #    {
966 #        CV * cv ;
967 #
968 EOF
969
970 for (@Func_name) {
971     $pname = shift(@Func_pname);
972     my $newXS = "newXS" ;
973     my $proto = "" ;
974
975     if ($ProtoXSUB{$pname}) {
976         $newXS = "newXSproto" ;
977         $proto = ", $ProtoXSUB{$pname}" ;
978     }
979
980     if ($XsubAliases{$pname}) {
981         $XsubAliases{$pname}{$pname} = 0 
982                 unless defined $XsubAliases{$pname}{$pname} ;
983         while ( ($name, $value) = each %{$XsubAliases{$pname}}) {
984             print Q<<"EOF" ;
985 #        cv = newXS(\"$name\", XS_$_, file);
986 #        XSANY.any_i32 = $value ;
987 EOF
988             print Q<<"EOF" if $proto ;
989 #        sv_setpv(cv, $ProtoXSUB{$pname}) ;
990 EOF
991         }
992     }
993     else {
994         print "        ${newXS}(\"$pname\", XS_$_, file$proto);\n";
995     }
996 }
997
998 print Q<<"EOF" if defined %XsubAliases ;
999 #    }
1000 EOF
1001
1002 if (@BootCode)
1003 {
1004     print "\n    /* Initialisation Section */\n" ;
1005     print grep (s/$/\n/, @BootCode) ;
1006     print "\n    /* End of Initialisation Section */\n\n" ;
1007 }
1008
1009 print Q<<"EOF";;
1010 #    ST(0) = &sv_yes;
1011 #    XSRETURN(1);
1012 #]]
1013 EOF
1014
1015 warn("Please specify prototyping behavior for $filename (see perlxs manual)\n") 
1016     unless $ProtoUsed ;
1017 &Exit;
1018
1019
1020 sub output_init {
1021     local($type, $num, $init) = @_;
1022     local($arg) = "ST(" . ($num - 1) . ")";
1023
1024     eval qq/print " $init\\\n"/;
1025 }
1026
1027 sub Warn
1028 {
1029     # work out the line number
1030     my $line_no = $line_no[@line_no - @line -1] ;
1031  
1032     print STDERR "@_ in $filename, line $line_no\n" ;
1033 }
1034
1035 sub blurt 
1036
1037     Warn @_ ;
1038     $errors ++ 
1039 }
1040
1041 sub death
1042 {
1043     Warn @_ ;
1044     exit 1 ;
1045 }
1046
1047 sub generate_init {
1048     local($type, $num, $var) = @_;
1049     local($arg) = "ST(" . ($num - 1) . ")";
1050     local($argoff) = $num - 1;
1051     local($ntype);
1052     local($tk);
1053
1054     $type = TidyType($type) ;
1055     blurt("Error: '$type' not in typemap"), return 
1056         unless defined($type_kind{$type});
1057
1058     ($ntype = $type) =~ s/\s*\*/Ptr/g;
1059     ($subtype = $ntype) =~ s/(?:Array)?(?:Ptr)?$//;
1060     $tk = $type_kind{$type};
1061     $tk =~ s/OBJ$/REF/ if $func_name =~ /DESTROY$/;
1062     $type =~ tr/:/_/;
1063     blurt("Error: No INPUT definition for type '$type' found"), return
1064         unless defined $input_expr{$tk} ;
1065     $expr = $input_expr{$tk};
1066     if ($expr =~ /DO_ARRAY_ELEM/) {
1067         blurt("Error: '$subtype' not in typemap"), return 
1068             unless defined($type_kind{$subtype});
1069         blurt("Error: No INPUT definition for type '$subtype' found"), return
1070             unless defined $input_expr{$type_kind{$subtype}} ;
1071         $subexpr = $input_expr{$type_kind{$subtype}};
1072         $subexpr =~ s/ntype/subtype/g;
1073         $subexpr =~ s/\$arg/ST(ix_$var)/g;
1074         $subexpr =~ s/\n\t/\n\t\t/g;
1075         $subexpr =~ s/is not of (.*")/[arg %d] is not of $1, ix_$var + 1/g;
1076         $subexpr =~ s/\$var/${var}[ix_$var - $argoff]/;
1077         $expr =~ s/DO_ARRAY_ELEM/$subexpr/;
1078     }
1079     if (defined($defaults{$var})) {
1080             $expr =~ s/(\t+)/$1    /g;
1081             $expr =~ s/        /\t/g;
1082             eval qq/print "\\t$var;\\n"/;
1083             $deferred .= eval qq/"\\n\\tif (items < $num)\\n\\t    $var = $defaults{$var};\\n\\telse {\\n$expr;\\n\\t}\\n"/;
1084     } elsif ($expr !~ /^\t\$var =/) {
1085             eval qq/print "\\t$var;\\n"/;
1086             $deferred .= eval qq/"\\n$expr;\\n"/;
1087     } else {
1088             eval qq/print "$expr;\\n"/;
1089     }
1090 }
1091
1092 sub generate_output {
1093     local($type, $num, $var) = @_;
1094     local($arg) = "ST(" . ($num - ($num != 0)) . ")";
1095     local($argoff) = $num - 1;
1096     local($ntype);
1097
1098     $type = TidyType($type) ;
1099     if ($type =~ /^array\(([^,]*),(.*)\)/) {
1100             print "\tsv_setpvn($arg, (char *)$var, $2 * sizeof($1)), XFree((char *)$var);\n";
1101     } else {
1102             blurt("Error: '$type' not in typemap"), return
1103                 unless defined($type_kind{$type});
1104             blurt("Error: No OUTPUT definition for type '$type' found"), return
1105                 unless defined $output_expr{$type_kind{$type}} ;
1106             ($ntype = $type) =~ s/\s*\*/Ptr/g;
1107             $ntype =~ s/\(\)//g;
1108             ($subtype = $ntype) =~ s/(?:Array)?(?:Ptr)?$//;
1109             $expr = $output_expr{$type_kind{$type}};
1110             if ($expr =~ /DO_ARRAY_ELEM/) {
1111                 blurt("Error: '$subtype' not in typemap"), return
1112                     unless defined($type_kind{$subtype});
1113                 blurt("Error: No OUTPUT definition for type '$subtype' found"), return
1114                     unless defined $output_expr{$type_kind{$subtype}} ;
1115                 $subexpr = $output_expr{$type_kind{$subtype}};
1116                 $subexpr =~ s/ntype/subtype/g;
1117                 $subexpr =~ s/\$arg/ST(ix_$var)/g;
1118                 $subexpr =~ s/\$var/${var}[ix_$var]/g;
1119                 $subexpr =~ s/\n\t/\n\t\t/g;
1120                 $expr =~ s/DO_ARRAY_ELEM\n/$subexpr/;
1121                 eval "print qq\a$expr\a";
1122             }
1123             elsif ($var eq 'RETVAL') {
1124                 if ($expr =~ /^\t\$arg = /) {
1125                     eval "print qq\a$expr\a";
1126                     print "\tsv_2mortal(ST(0));\n";
1127                 }
1128                 else {
1129                     print "\tST(0) = sv_newmortal();\n";
1130                     eval "print qq\a$expr\a";
1131                 }
1132             }
1133             elsif ($arg =~ /^ST\(\d+\)$/) {
1134                 eval "print qq\a$expr\a";
1135             }
1136     }
1137 }
1138
1139 sub map_type {
1140     my($type) = @_;
1141
1142     $type =~ tr/:/_/;
1143     $type =~ s/^array\(([^,]*),(.*)\).*/$1 */s;
1144     $type;
1145 }
1146
1147
1148 sub Exit {
1149 # If this is VMS, the exit status has meaning to the shell, so we
1150 # use a predictable value (SS$_Normal or SS$_Abort) rather than an
1151 # arbitrary number.
1152     exit ($Is_VMS ? ($errors ? 44 : 1) : $errors) ;
1153 }