44a3bf191b55fc863be277ca09e04c37003eb612
[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<-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 =back
48
49 =head1 ENVIRONMENT
50
51 No environment variables are used.
52
53 =head1 AUTHOR
54
55 Larry Wall
56
57 =head1 MODIFICATION HISTORY
58
59 See the file F<changes.pod>.
60
61 =head1 SEE ALSO
62
63 perl(1), perlapi(1)
64
65 =cut
66
67 # Global Constants
68 $XSUBPP_version = "1.922";
69 require 5.001;
70
71 $usage = "Usage: xsubpp [-v] [-C++] [-except] [-s pattern] [-typemap typemap]... file.xs\n";
72
73 $except = "";
74 SWITCH: while (@ARGV and $ARGV[0] =~ /^-./) {
75     $flag = shift @ARGV;
76     $flag =~ s/^-// ;
77     $spat = shift,      next SWITCH     if $flag eq 's';
78     $cplusplus = 1,     next SWITCH     if $flag eq 'C++';
79     $except = " TRY",   next SWITCH     if $flag eq 'except';
80     push(@tm,shift),    next SWITCH     if $flag eq 'typemap';
81     (print "xsubpp version $XSUBPP_version\n"), exit    
82         if $flag eq 'v';
83     die $usage;
84 }
85 @ARGV == 1 or die $usage;
86 chomp($pwd = `pwd`);
87 # Check for error message from VMS
88 if ($pwd =~ /unrecognized command verb/) { $Is_VMS = 1; $pwd = $ENV{DEFAULT} }
89 ($dir, $filename) = $ARGV[0] =~ m#(.*)/(.*)#
90         or ($dir, $filename) = $ARGV[0] =~ m#(.*[>\]])(.*)#
91         or ($dir, $filename) = ('.', $ARGV[0]);
92 chdir($dir);
93
94 sub TrimWhitespace
95 {
96     $_[0] =~ s/^\s+|\s+$//go ;
97 }
98
99 sub TidyType
100 {
101     local ($_) = @_ ;
102
103     # rationalise any '*' by joining them into bunches and removing whitespace
104     s#\s*(\*+)\s*#$1#g;
105     s#(\*+)# $1 #g ;
106
107     # change multiple whitespace into a single space
108     s/\s+/ /g ;
109     
110     # trim leading & trailing whitespace
111     TrimWhitespace($_) ;
112
113     $_ ;
114 }
115
116 $typemap = shift @ARGV;
117 foreach $typemap (@tm) {
118     die "Can't find $typemap in $pwd\n" unless -r $typemap;
119 }
120 unshift @tm, qw(../../../../lib/ExtUtils/typemap ../../../lib/ExtUtils/typemap
121                 ../../lib/ExtUtils/typemap ../../../typemap ../../typemap
122                 ../typemap typemap);
123 foreach $typemap (@tm) {
124     next unless -e $typemap ;
125     # skip directories, binary files etc.
126     warn("Warning: ignoring non-text typemap file '$typemap'\n"), next 
127         unless -T $typemap ;
128     open(TYPEMAP, $typemap) 
129         or warn ("Warning: could not open typemap file '$typemap': $!\n"), next;
130     $mode = 'Typemap';
131     $junk = "" ;
132     $current = \$junk;
133     while (<TYPEMAP>) {
134         next if /^\s*#/;
135         if (/^INPUT\s*$/)   { $mode = 'Input';   $current = \$junk;  next; }
136         if (/^OUTPUT\s*$/)  { $mode = 'Output';  $current = \$junk;  next; }
137         if (/^TYPEMAP\s*$/) { $mode = 'Typemap'; $current = \$junk;  next; }
138         if ($mode eq 'Typemap') {
139             chomp;
140             my $line = $_ ;
141             TrimWhitespace($_) ;
142             # skip blank lines and comment lines
143             next if /^$/ or /^#/ ;
144             my($type,$kind) = /^\s*(.*?\S)\s+(\S+)\s*$/ or
145                 warn("Warning: File '$typemap' Line $. '$line' TYPEMAP entry needs 2 columns\n"), next;
146             $type_kind{TidyType($type)} = $kind ;
147         }
148         elsif (/^\s/) {
149             $$current .= $_;
150         }
151         elsif ($mode eq 'Input') {
152             s/\s+$//;
153             $input_expr{$_} = '';
154             $current = \$input_expr{$_};
155         }
156         else {
157             s/\s+$//;
158             $output_expr{$_} = '';
159             $current = \$output_expr{$_};
160         }
161     }
162     close(TYPEMAP);
163 }
164
165 foreach $key (keys %input_expr) {
166     $input_expr{$key} =~ s/\n+$//;
167 }
168
169 $END = "!End!\n\n";             # "impossible" keyword (multiple newline)
170
171 # Match an XS keyword
172 $BLOCK_re= "\\s*(REQUIRE|BOOT|CASE|PREINIT|INPUT|INIT|CODE|PPCODE|OUTPUT|CLEANUP|ALIAS|$END)\\s*:";
173
174 # Input:  ($_, @line) == unparsed input.
175 # Output: ($_, @line) == (rest of line, following lines).
176 # Return: the matched keyword if found, otherwise 0
177 sub check_keyword {
178         $_ = shift(@line) while !/\S/ && @line;
179         s/^(\s*)($_[0])\s*:\s*(?:#.*)?/$1/s && $2;
180 }
181
182
183 sub print_section {
184     $_ = shift(@line) while !/\S/ && @line;
185     for (;  defined($_) && !/^$BLOCK_re/o;  $_ = shift(@line)) {
186         print "$_\n";
187     }
188 }
189
190 sub CASE_handler {
191     blurt ("Error: `CASE:' after unconditional `CASE:'")
192         if $condnum && $cond eq '';
193     $cond = $_;
194     TrimWhitespace($cond);
195     print "   ", ($condnum++ ? " else" : ""), ($cond ? " if ($cond)\n" : "\n");
196     $_ = '' ;
197 }
198
199 sub INPUT_handler {
200     for (;  !/^$BLOCK_re/o;  $_ = shift(@line)) {
201         last if /^\s*NOT_IMPLEMENTED_YET/;
202         next unless /\S/;       # skip blank lines 
203
204         TrimWhitespace($_) ;
205         my $line = $_ ;
206
207         # remove trailing semicolon if no initialisation
208         s/\s*;$//g unless /=/ ;
209
210         # check for optional initialisation code
211         my $var_init = '' ;
212         $var_init = $1 if s/\s*(=.*)$//s ;
213         $var_init =~ s/"/\\"/g;
214
215         s/\s+/ /g;
216         my ($var_type, $var_addr, $var_name) = /^(.*?[^& ]) *(\&?) *\b(\w+)$/s
217             or blurt("Error: invalid argument declaration '$line'"), next;
218
219         # Check for duplicate definitions
220         blurt ("Error: duplicate definition of argument '$var_name' ignored"), next
221             if $arg_list{$var_name} ++  ;
222
223         $thisdone |= $var_name eq "THIS";
224         $retvaldone |= $var_name eq "RETVAL";
225         $var_types{$var_name} = $var_type;
226         print "\t" . &map_type($var_type);
227         $var_num = $args_match{$var_name};
228         if ($var_addr) {
229             $var_addr{$var_name} = 1;
230             $func_args =~ s/\b($var_name)\b/&$1/;
231         }
232         if ($var_init =~ /^=\s*NO_INIT\s*;?\s*$/) {
233             print "\t$var_name;\n";
234         } elsif ($var_init =~ /\S/) {
235             &output_init($var_type, $var_num, "$var_name $var_init");
236         } elsif ($var_num) {
237             # generate initialization code
238             &generate_init($var_type, $var_num, $var_name);
239         } else {
240             print ";\n";
241         }
242     }
243 }
244
245 sub OUTPUT_handler {
246     for (;  !/^$BLOCK_re/o;  $_ = shift(@line)) {
247         next unless /\S/;
248         my ($outarg, $outcode) = /^\s*(\S+)\s*(.*?)\s*$/s ;
249         blurt ("Error: duplicate OUTPUT argument '$outarg' ignored"), next
250             if $outargs{$outarg} ++ ;
251         if (!$gotRETVAL and $outarg eq 'RETVAL') {
252             # deal with RETVAL last
253             $RETVAL_code = $outcode ;
254             $gotRETVAL = 1 ;
255             next ;
256         }
257         blurt ("Error: OUTPUT $outarg not an argument"), next
258             unless defined($args_match{$outarg});
259         blurt("Error: No input definition for OUTPUT argument '$outarg' - ignored"), next
260             unless defined $var_types{$outarg} ;
261         if ($outcode) {
262             print "\t$outcode\n";
263         } else {
264             $var_num = $args_match{$outarg};
265             &generate_output($var_types{$outarg}, $var_num, $outarg); 
266         }
267     }
268 }
269
270 sub GetAliases
271 {
272     my ($line) = @_ ;
273     my ($orig) = $line ;
274     my ($alias) ;
275     my ($value) ;
276
277     # Parse alias definitions
278     # format is
279     #    alias = value alias = value ...
280
281     while ($line =~ s/^\s*([\w:]+)\s*=\s*(\w+)\s*//) {
282         $alias = $1 ;
283         $orig_alias = $alias ;
284         $value = $2 ;
285
286         # check for optional package definition in the alias
287         $alias = $Packprefix . $alias if $alias !~ /::/ ;
288         
289         # check for duplicate alias name & duplicate value
290         Warn("Warning: Ignoring duplicate alias '$orig_alias'")
291             if defined $XsubAliases{$pname}{$alias} ;
292
293         Warn("Warning: Aliases '$orig_alias' and '$XsubAliasValues{$pname}{$value}' have identical values")
294             if $XsubAliasValues{$pname}{$value} ;
295
296         $XsubAliases{$pname}{$alias} = $value ;
297         $XsubAliasValues{$pname}{$value} = $orig_alias ;
298     }
299
300     blurt("Error: Cannot parse ALIAS definitions from '$orig'")
301         if $line ;
302 }
303
304 sub ALIAS_handler
305 {
306     for (;  !/^$BLOCK_re/o;  $_ = shift(@line)) {
307         next unless /\S/;
308         TrimWhitespace($_) ;
309         GetAliases($_) if $_ ;
310     }
311 }
312
313 sub REQUIRE_handler
314 {
315     # the rest of the current line should contain a version number
316     my ($Ver) = $_ ;
317
318     TrimWhitespace($Ver) ;
319
320     death ("Error: REQUIRE expects a version number")
321         unless $Ver ;
322
323     # check that the version number is of the form n.n
324     death ("Error: REQUIRE: expected a number, got '$Ver'")
325         unless $Ver =~ /^\d+(\.\d*)?/ ;
326
327     death ("Error: xsubpp $Ver (or better) required--this is only $XSUBPP_version.")
328         unless $XSUBPP_version >= $Ver ; 
329 }
330
331 sub check_cpp {
332     my @cpp = grep(/^\#\s*(?:if|e\w+)/, @line);
333     if (@cpp) {
334         my ($cpp, $cpplevel);
335         for $cpp (@cpp) {
336             if ($cpp =~ /^\#\s*if/) {
337                 $cpplevel++;
338             } elsif (!$cpplevel) {
339                 Warn("Warning: #else/elif/endif without #if in this function");
340                 return;
341             } elsif ($cpp =~ /^\#\s*endif/) {
342                 $cpplevel--;
343             }
344         }
345         Warn("Warning: #if without #endif in this function") if $cpplevel;
346     }
347 }
348
349
350 sub Q {
351     my($text) = @_;
352     $text =~ tr/#//d;
353     $text =~ s/\[\[/{/g;
354     $text =~ s/\]\]/}/g;
355     $text;
356 }
357
358 open(F, $filename) or die "cannot open $filename: $!\n";
359
360 # Identify the version of xsubpp used
361 print <<EOM ;
362 /*
363  * This file was generated automatically by xsubpp version $XSUBPP_version from the 
364  * contents of $filename. Don't edit this file, edit $filename instead.
365  *
366  *      ANY CHANGES MADE HERE WILL BE LOST! 
367  *
368  */
369
370 EOM
371  
372
373 while (<F>) {
374     last if ($Module, $Package, $Prefix) =
375         /^MODULE\s*=\s*([\w:]+)(?:\s+PACKAGE\s*=\s*([\w:]+))?(?:\s+PREFIX\s*=\s*(\S+))?\s*$/;
376     print $_;
377 }
378 &Exit unless defined $_;
379
380 my $lastline    = $_;
381 my $lastline_no = $.;
382
383
384 # Read next xsub into @line from ($lastline, <F>).
385 sub fetch_para {
386     # parse paragraph
387     @line = ();
388     @line_no = () ;
389     return 0 unless defined $lastline;
390
391     if ($lastline =~
392         /^MODULE\s*=\s*([\w:]+)(?:\s+PACKAGE\s*=\s*([\w:]+))?(?:\s+PREFIX\s*=\s*(\S+))?\s*$/) {
393         $Module = $1;
394         $Package = defined($2) ? $2 : '';       # keep -w happy
395         $Prefix  = defined($3) ? $3 : '';       # keep -w happy
396         ($Module_cname = $Module) =~ s/\W/_/g;
397         ($Packid = $Package) =~ tr/:/_/;
398         $Packprefix = $Package;
399         $Packprefix .= "::" if $Packprefix ne "";
400         $lastline = "";
401     }
402
403     for(;;) {
404         if ($lastline !~ /^\s*#/ ||
405             $lastline =~ /^#[ \t]*(?:(?:if|ifn?def|else|elif|endif|define|undef|pragma)\b|include\s*["<].*[>"])/) {
406             last if $lastline =~ /^\S/ && @line && $line[-1] eq "";
407             push(@line, $lastline);
408             push(@line_no, $lastline_no) ;
409         }
410
411         # Read next line and continuation lines
412         last unless defined($lastline = <F>);
413         $lastline_no = $.;
414         my $tmp_line;
415         $lastline .= $tmp_line
416             while ($lastline =~ /\\$/ && defined($tmp_line = <F>));
417             
418         chomp $lastline;
419         $lastline =~ s/^\s+$//;
420     }
421     pop(@line), pop(@line_no) while @line && $line[-1] eq "";
422     1;
423 }
424
425 PARAGRAPH:
426 while (fetch_para()) {
427     # Print initial preprocessor statements and blank lines
428     print shift(@line), "\n"
429         while @line && $line[0] !~ /^[^\#]/;
430
431     next PARAGRAPH unless @line;
432
433     death ("Code is not inside a function")
434         if $line[0] =~ /^\s/;
435
436     # initialize info arrays
437     undef(%args_match);
438     undef(%var_types);
439     undef(%var_addr);
440     undef(%defaults);
441     undef($class);
442     undef($static);
443     undef($elipsis);
444     undef($wantRETVAL) ;
445     undef(%arg_list) ;
446
447     $_ = shift(@line);
448     if (check_keyword("REQUIRE")) {
449         REQUIRE_handler() ; 
450         next PARAGRAPH unless @line ;
451         $_ = shift(@line);
452     }
453
454     if (check_keyword("BOOT")) {
455         &check_cpp;
456         push (@BootCode, $_, @line, "") ;
457         next PARAGRAPH ;
458     }
459
460
461     # extract return type, function name and arguments
462     my($ret_type) = TidyType($_);
463
464     # a function definition needs at least 2 lines
465     blurt ("Error: Function definition too short '$ret_type'"), next PARAGRAPH
466         unless @line ;
467
468     $static = 1 if $ret_type =~ s/^static\s+//;
469
470     $func_header = shift(@line);
471     blurt ("Error: Cannot parse function definition from '$func_header'"), next PARAGRAPH
472         unless $func_header =~ /^(?:([\w:]*)::)?(\w+)\s*\(\s*(.*?)\s*\)\s*$/s;
473
474     ($class, $func_name, $orig_args) =  ($1, $2, $3) ;
475     ($pname = $func_name) =~ s/^($Prefix)?/$Packprefix/;
476
477     # Check for duplicate function definition
478     if (defined $Func_name{"${Packid}_$func_name"} ) {
479        Warn("Warning: duplicate function definition '$func_name' detected") 
480     }
481     else {
482         push(@Func_name, "${Packid}_$func_name");
483         push(@Func_pname, $pname);
484     }
485     $Func_name{"${Packid}_$func_name"} ++ ;
486
487     @args = split(/\s*,\s*/, $orig_args);
488     if (defined($class)) {
489         my $arg0 = (defined($static) ? "CLASS" : "THIS");
490         unshift(@args, $arg0);
491         ($orig_args = "$arg0, $orig_args") =~ s/^$arg0, $/$arg0/;
492     }
493     $orig_args =~ s/"/\\"/g;
494     $min_args = $num_args = @args;
495     foreach $i (0..$num_args-1) {
496             if ($args[$i] =~ s/\.\.\.//) {
497                     $elipsis = 1;
498                     $min_args--;
499                     if ($args[$i] eq '' && $i == $num_args - 1) {
500                         pop(@args);
501                         last;
502                     }
503             }
504             if ($args[$i] =~ /^([^=]*[^\s=])\s*=\s*(.*)/s) {
505                     $min_args--;
506                     $args[$i] = $1;
507                     $defaults{$args[$i]} = $2;
508                     $defaults{$args[$i]} =~ s/"/\\"/g;
509             }
510     }
511     if (defined($class)) {
512             $func_args = join(", ", @args[1..$#args]);
513     } else {
514             $func_args = join(", ", @args);
515     }
516     @args_match{@args} = 1..@args;
517
518     $PPCODE = grep(/^\s*PPCODE\s*:/, @line);
519     $ALIAS  = grep(/^\s*ALIAS\s*:/,  @line);
520
521     # print function header
522     print Q<<"EOF";
523 #XS(XS_${Packid}_$func_name)
524 #[[
525 #    dXSARGS;
526 EOF
527     print Q<<"EOF" if $ALIAS ;
528 #    dXSI32;
529 EOF
530     if ($elipsis) {
531         $cond = ($min_args ? qq(items < $min_args) : 0);
532     }
533     elsif ($min_args == $num_args) {
534         $cond = qq(items != $min_args);
535     }
536     else {
537         $cond = qq(items < $min_args || items > $num_args);
538     }
539
540     print Q<<"EOF" if $except;
541 #    char errbuf[1024];
542 #    *errbuf = '\0';
543 EOF
544
545     if ($ALIAS) 
546       { print Q<<"EOF" if $cond }
547 #    if ($cond)
548 #       croak("Usage: %s($orig_args)", GvNAME(CvGV(cv)));
549 EOF
550     else 
551       { print Q<<"EOF" if $cond }
552 #    if ($cond)
553 #       croak("Usage: $pname($orig_args)");
554 EOF
555
556     print Q<<"EOF" if $PPCODE;
557 #    SP -= items;
558 EOF
559
560     # Now do a block of some sort.
561
562     $condnum = 0;
563     $cond = '';                 # last CASE: condidional
564     push(@line, "$END:");
565     push(@line_no, $line_no[-1]);
566     $_ = '';
567     &check_cpp;
568     while (@line) {
569         &CASE_handler if check_keyword("CASE");
570         print Q<<"EOF";
571 #   $except [[
572 EOF
573
574         # do initialization of input variables
575         $thisdone = 0;
576         $retvaldone = 0;
577         $deferred = "";
578         %arg_list = () ;
579         $gotRETVAL = 0;
580
581         &INPUT_handler;
582         my $kwd;
583         while ($kwd = check_keyword("INPUT|PREINIT")) {
584             if ($kwd eq 'PREINIT') { &print_section; } else { &INPUT_handler; }
585         }
586         if (!$thisdone && defined($class)) {
587             if (defined($static)) {
588                 print "\tchar *";
589                 $var_types{"CLASS"} = "char *";
590                 &generate_init("char *", 1, "CLASS");
591             }
592             else {
593                 print "\t$class *";
594                 $var_types{"THIS"} = "$class *";
595                 &generate_init("$class *", 1, "THIS");
596             }
597         }
598
599         # do code
600         if (/^\s*NOT_IMPLEMENTED_YET/) {
601                 print "\ncroak(\"$pname: not implemented yet\");\n";
602         } else {
603                 if ($ret_type ne "void") {
604                         print "\t" . &map_type($ret_type) . "\tRETVAL;\n"
605                                 if !$retvaldone;
606                         $args_match{"RETVAL"} = 0;
607                         $var_types{"RETVAL"} = $ret_type;
608                 }
609                 print $deferred;
610                 while ($kwd = check_keyword("INIT|ALIAS")) {
611                     if ($kwd eq 'INIT') {
612                         &print_section
613                     }
614                     else {
615                         ALIAS_handler
616                     }
617                 }
618
619                 if (check_keyword("PPCODE")) {
620                         &print_section;
621                         death ("PPCODE must be last thing") if @line;
622                         print "\tPUTBACK;\n\treturn;\n";
623                 } elsif (check_keyword("CODE")) {
624                         &print_section;
625                 } elsif ($func_name eq "DESTROY") {
626                         print "\n\t";
627                         print "delete THIS;\n";
628                 } else {
629                         print "\n\t";
630                         if ($ret_type ne "void") {
631                                 print "RETVAL = ";
632                                 $wantRETVAL = 1;
633                         }
634                         if (defined($static)) {
635                             if ($func_name =~ /^new/) {
636                                 $func_name = "$class";
637                             } else {
638                                 print "${class}::";
639                             }
640                         } elsif (defined($class)) {
641                                 print "THIS->";
642                         }
643                         $func_name =~ s/^($spat)//
644                             if defined($spat);
645                         print "$func_name($func_args);\n";
646                 }
647         }
648
649         # do output variables
650         $gotRETVAL = 0;
651         undef $RETVAL_code ;
652         undef %outargs ;
653         &OUTPUT_handler while check_keyword("OUTPUT");
654
655         # all OUTPUT done, so now push the return value on the stack
656         if ($gotRETVAL && $RETVAL_code) {
657             print "\t$RETVAL_code\n";
658         } elsif ($gotRETVAL || $wantRETVAL) {
659             &generate_output($ret_type, 0, 'RETVAL');
660         }
661
662         # do cleanup
663         &print_section while check_keyword("CLEANUP");
664
665         # print function trailer
666         print Q<<EOF;
667 #    ]]
668 EOF
669         print Q<<EOF if $except;
670 #    BEGHANDLERS
671 #    CATCHALL
672 #       sprintf(errbuf, "%s: %s\\tpropagated", Xname, Xreason);
673 #    ENDHANDLERS
674 EOF
675         if (check_keyword("CASE")) {
676             blurt ("Error: No `CASE:' at top of function")
677                 unless $condnum;
678             $_ = "CASE: $_";    # Restore CASE: label
679             next;
680         }
681         last if $_ eq "$END:";
682         death(/^$BLOCK_re/o ? "Misplaced `$1:'" : "Junk at end of function");
683     }
684
685     print Q<<EOF if $except;
686 #    if (errbuf[0])
687 #       croak(errbuf);
688 EOF
689
690     print Q<<EOF unless $PPCODE;
691 #    XSRETURN(1);
692 EOF
693
694     print Q<<EOF;
695 #]]
696 #
697 EOF
698 }
699
700 # print initialization routine
701 print qq/extern "C"\n/ if $cplusplus;
702 print Q<<"EOF";
703 #XS(boot_$Module_cname)
704 #[[
705 #    dXSARGS;
706 #    char* file = __FILE__;
707 #
708 EOF
709
710 print Q<<"EOF" if defined %XsubAliases ;
711 #    {
712 #        CV * cv ;
713 #
714 EOF
715
716 for (@Func_name) {
717     $pname = shift(@Func_pname);
718
719     if ($XsubAliases{$pname}) {
720         $XsubAliases{$pname}{$pname} = 0 
721                 unless defined $XsubAliases{$pname}{$pname} ;
722         while ( ($name, $value) = each %{$XsubAliases{$pname}}) {
723             print Q<<"EOF" ;
724 #        cv = newXS(\"$name\", XS_$_, file);
725 #        XSANY.any_i32 = $value ;
726 EOF
727         }
728     }
729     else {
730         print "        newXS(\"$pname\", XS_$_, file);\n";
731     }
732 }
733
734 print Q<<"EOF" if defined %XsubAliases ;
735 #    }
736 EOF
737
738 if (@BootCode)
739 {
740     print "\n    /* Initialisation Section */\n" ;
741     print grep (s/$/\n/, @BootCode) ;
742     print "\n    /* End of Initialisation Section */\n\n" ;
743 }
744
745 print Q<<"EOF";;
746 #    ST(0) = &sv_yes;
747 #    XSRETURN(1);
748 #]]
749 EOF
750
751 &Exit;
752
753
754 sub output_init {
755     local($type, $num, $init) = @_;
756     local($arg) = "ST(" . ($num - 1) . ")";
757
758     eval qq/print " $init\\\n"/;
759 }
760
761 sub Warn
762 {
763     # work out the line number
764     my $line_no = $line_no[@line_no - @line -1] ;
765  
766     print STDERR "@_ in $filename, line $line_no\n" ;
767 }
768
769 sub blurt 
770
771     Warn @_ ;
772     $errors ++ 
773 }
774
775 sub death
776 {
777     Warn @_ ;
778     exit 1 ;
779 }
780
781 sub generate_init {
782     local($type, $num, $var) = @_;
783     local($arg) = "ST(" . ($num - 1) . ")";
784     local($argoff) = $num - 1;
785     local($ntype);
786     local($tk);
787
788     $type = TidyType($type) ;
789     blurt("Error: '$type' not in typemap"), return 
790         unless defined($type_kind{$type});
791
792     ($ntype = $type) =~ s/\s*\*/Ptr/g;
793     ($subtype = $ntype) =~ s/(?:Array)?(?:Ptr)?$//;
794     $tk = $type_kind{$type};
795     $tk =~ s/OBJ$/REF/ if $func_name =~ /DESTROY$/;
796     $type =~ tr/:/_/;
797     blurt("Error: No INPUT definition for type '$type' found"), return
798         unless defined $input_expr{$tk} ;
799     $expr = $input_expr{$tk};
800     if ($expr =~ /DO_ARRAY_ELEM/) {
801         blurt("Error: '$subtype' not in typemap"), return 
802             unless defined($type_kind{$subtype});
803         blurt("Error: No INPUT definition for type '$subtype' found"), return
804             unless defined $input_expr{$type_kind{$subtype}} ;
805         $subexpr = $input_expr{$type_kind{$subtype}};
806         $subexpr =~ s/ntype/subtype/g;
807         $subexpr =~ s/\$arg/ST(ix_$var)/g;
808         $subexpr =~ s/\n\t/\n\t\t/g;
809         $subexpr =~ s/is not of (.*")/[arg %d] is not of $1, ix_$var + 1/g;
810         $subexpr =~ s/\$var/${var}[ix_$var - $argoff]/;
811         $expr =~ s/DO_ARRAY_ELEM/$subexpr/;
812     }
813     if (defined($defaults{$var})) {
814             $expr =~ s/(\t+)/$1    /g;
815             $expr =~ s/        /\t/g;
816             eval qq/print "\\t$var;\\n"/;
817             $deferred .= eval qq/"\\n\\tif (items < $num)\\n\\t    $var = $defaults{$var};\\n\\telse {\\n$expr;\\n\\t}\\n"/;
818     } elsif ($expr !~ /^\t\$var =/) {
819             eval qq/print "\\t$var;\\n"/;
820             $deferred .= eval qq/"\\n$expr;\\n"/;
821     } else {
822             eval qq/print "$expr;\\n"/;
823     }
824 }
825
826 sub generate_output {
827     local($type, $num, $var) = @_;
828     local($arg) = "ST(" . ($num - ($num != 0)) . ")";
829     local($argoff) = $num - 1;
830     local($ntype);
831
832     $type = TidyType($type) ;
833     if ($type =~ /^array\(([^,]*),(.*)\)/) {
834             print "\tsv_setpvn($arg, (char *)$var, $2 * sizeof($1)), XFree((char *)$var);\n";
835     } else {
836             blurt("Error: '$type' not in typemap"), return
837                 unless defined($type_kind{$type});
838             blurt("Error: No OUTPUT definition for type '$type' found"), return
839                 unless defined $output_expr{$type_kind{$type}} ;
840             ($ntype = $type) =~ s/\s*\*/Ptr/g;
841             $ntype =~ s/\(\)//g;
842             ($subtype = $ntype) =~ s/(?:Array)?(?:Ptr)?$//;
843             $expr = $output_expr{$type_kind{$type}};
844             if ($expr =~ /DO_ARRAY_ELEM/) {
845                 blurt("Error: '$subtype' not in typemap"), return
846                     unless defined($type_kind{$subtype});
847                 blurt("Error: No OUTPUT definition for type '$subtype' found"), return
848                     unless defined $output_expr{$type_kind{$subtype}} ;
849                 $subexpr = $output_expr{$type_kind{$subtype}};
850                 $subexpr =~ s/ntype/subtype/g;
851                 $subexpr =~ s/\$arg/ST(ix_$var)/g;
852                 $subexpr =~ s/\$var/${var}[ix_$var]/g;
853                 $subexpr =~ s/\n\t/\n\t\t/g;
854                 $expr =~ s/DO_ARRAY_ELEM\n/$subexpr/;
855                 eval "print qq\a$expr\a";
856             }
857             elsif ($var eq 'RETVAL') {
858                 if ($expr =~ /^\t\$arg = /) {
859                     eval "print qq\a$expr\a";
860                     print "\tsv_2mortal(ST(0));\n";
861                 }
862                 else {
863                     print "\tST(0) = sv_newmortal();\n";
864                     eval "print qq\a$expr\a";
865                 }
866             }
867             elsif ($arg =~ /^ST\(\d+\)$/) {
868                 eval "print qq\a$expr\a";
869             }
870     }
871 }
872
873 sub map_type {
874     my($type) = @_;
875
876     $type =~ tr/:/_/;
877     $type =~ s/^array\(([^,]*),(.*)\).*/$1 */s;
878     $type;
879 }
880
881
882 sub Exit {
883 # If this is VMS, the exit status has meaning to the shell, so we
884 # use a predictable value (SS$_Abort) rather than an arbitrary
885 # number.
886     exit ($Is_VMS ? 44 : $errors) ;
887 }