1*0Sstevel@tonic-gate#!./miniperl 2*0Sstevel@tonic-gate 3*0Sstevel@tonic-gate=head1 NAME 4*0Sstevel@tonic-gate 5*0Sstevel@tonic-gatexsubpp - compiler to convert Perl XS code into C code 6*0Sstevel@tonic-gate 7*0Sstevel@tonic-gate=head1 SYNOPSIS 8*0Sstevel@tonic-gate 9*0Sstevel@tonic-gateB<xsubpp> [B<-v>] [B<-C++>] [B<-except>] [B<-s pattern>] [B<-prototypes>] [B<-noversioncheck>] [B<-nolinenumbers>] [B<-nooptimize>] [B<-typemap typemap>] ... file.xs 10*0Sstevel@tonic-gate 11*0Sstevel@tonic-gate=head1 DESCRIPTION 12*0Sstevel@tonic-gate 13*0Sstevel@tonic-gateThis compiler is typically run by the makefiles created by L<ExtUtils::MakeMaker>. 14*0Sstevel@tonic-gate 15*0Sstevel@tonic-gateI<xsubpp> will compile XS code into C code by embedding the constructs 16*0Sstevel@tonic-gatenecessary to let C functions manipulate Perl values and creates the glue 17*0Sstevel@tonic-gatenecessary to let Perl access those functions. The compiler uses typemaps to 18*0Sstevel@tonic-gatedetermine how to map C function parameters and variables to Perl values. 19*0Sstevel@tonic-gate 20*0Sstevel@tonic-gateThe compiler will search for typemap files called I<typemap>. It will use 21*0Sstevel@tonic-gatethe following search path to find default typemaps, with the rightmost 22*0Sstevel@tonic-gatetypemap taking precedence. 23*0Sstevel@tonic-gate 24*0Sstevel@tonic-gate ../../../typemap:../../typemap:../typemap:typemap 25*0Sstevel@tonic-gate 26*0Sstevel@tonic-gate=head1 OPTIONS 27*0Sstevel@tonic-gate 28*0Sstevel@tonic-gateNote that the C<XSOPT> MakeMaker option may be used to add these options to 29*0Sstevel@tonic-gateany makefiles generated by MakeMaker. 30*0Sstevel@tonic-gate 31*0Sstevel@tonic-gate=over 5 32*0Sstevel@tonic-gate 33*0Sstevel@tonic-gate=item B<-C++> 34*0Sstevel@tonic-gate 35*0Sstevel@tonic-gateAdds ``extern "C"'' to the C code. 36*0Sstevel@tonic-gate 37*0Sstevel@tonic-gate=item B<-hiertype> 38*0Sstevel@tonic-gate 39*0Sstevel@tonic-gateRetains '::' in type names so that C++ hierachical types can be mapped. 40*0Sstevel@tonic-gate 41*0Sstevel@tonic-gate=item B<-except> 42*0Sstevel@tonic-gate 43*0Sstevel@tonic-gateAdds exception handling stubs to the C code. 44*0Sstevel@tonic-gate 45*0Sstevel@tonic-gate=item B<-typemap typemap> 46*0Sstevel@tonic-gate 47*0Sstevel@tonic-gateIndicates that a user-supplied typemap should take precedence over the 48*0Sstevel@tonic-gatedefault typemaps. This option may be used multiple times, with the last 49*0Sstevel@tonic-gatetypemap having the highest precedence. 50*0Sstevel@tonic-gate 51*0Sstevel@tonic-gate=item B<-v> 52*0Sstevel@tonic-gate 53*0Sstevel@tonic-gatePrints the I<xsubpp> version number to standard output, then exits. 54*0Sstevel@tonic-gate 55*0Sstevel@tonic-gate=item B<-prototypes> 56*0Sstevel@tonic-gate 57*0Sstevel@tonic-gateBy default I<xsubpp> will not automatically generate prototype code for 58*0Sstevel@tonic-gateall xsubs. This flag will enable prototypes. 59*0Sstevel@tonic-gate 60*0Sstevel@tonic-gate=item B<-noversioncheck> 61*0Sstevel@tonic-gate 62*0Sstevel@tonic-gateDisables the run time test that determines if the object file (derived 63*0Sstevel@tonic-gatefrom the C<.xs> file) and the C<.pm> files have the same version 64*0Sstevel@tonic-gatenumber. 65*0Sstevel@tonic-gate 66*0Sstevel@tonic-gate=item B<-nolinenumbers> 67*0Sstevel@tonic-gate 68*0Sstevel@tonic-gatePrevents the inclusion of `#line' directives in the output. 69*0Sstevel@tonic-gate 70*0Sstevel@tonic-gate=item B<-nooptimize> 71*0Sstevel@tonic-gate 72*0Sstevel@tonic-gateDisables certain optimizations. The only optimization that is currently 73*0Sstevel@tonic-gateaffected is the use of I<target>s by the output C code (see L<perlguts>). 74*0Sstevel@tonic-gateThis may significantly slow down the generated code, but this is the way 75*0Sstevel@tonic-gateB<xsubpp> of 5.005 and earlier operated. 76*0Sstevel@tonic-gate 77*0Sstevel@tonic-gate=item B<-noinout> 78*0Sstevel@tonic-gate 79*0Sstevel@tonic-gateDisable recognition of C<IN>, C<OUT_LIST> and C<INOUT_LIST> declarations. 80*0Sstevel@tonic-gate 81*0Sstevel@tonic-gate=item B<-noargtypes> 82*0Sstevel@tonic-gate 83*0Sstevel@tonic-gateDisable recognition of ANSI-like descriptions of function signature. 84*0Sstevel@tonic-gate 85*0Sstevel@tonic-gate=back 86*0Sstevel@tonic-gate 87*0Sstevel@tonic-gate=head1 ENVIRONMENT 88*0Sstevel@tonic-gate 89*0Sstevel@tonic-gateNo environment variables are used. 90*0Sstevel@tonic-gate 91*0Sstevel@tonic-gate=head1 AUTHOR 92*0Sstevel@tonic-gate 93*0Sstevel@tonic-gateLarry Wall 94*0Sstevel@tonic-gate 95*0Sstevel@tonic-gate=head1 MODIFICATION HISTORY 96*0Sstevel@tonic-gate 97*0Sstevel@tonic-gateSee the file F<changes.pod>. 98*0Sstevel@tonic-gate 99*0Sstevel@tonic-gate=head1 SEE ALSO 100*0Sstevel@tonic-gate 101*0Sstevel@tonic-gateperl(1), perlxs(1), perlxstut(1) 102*0Sstevel@tonic-gate 103*0Sstevel@tonic-gate=cut 104*0Sstevel@tonic-gate 105*0Sstevel@tonic-gaterequire 5.002; 106*0Sstevel@tonic-gateuse Cwd; 107*0Sstevel@tonic-gateuse vars qw($cplusplus $hiertype); 108*0Sstevel@tonic-gateuse vars '%v'; 109*0Sstevel@tonic-gate 110*0Sstevel@tonic-gateuse Config; 111*0Sstevel@tonic-gate 112*0Sstevel@tonic-gatesub Q ; 113*0Sstevel@tonic-gate 114*0Sstevel@tonic-gate# Global Constants 115*0Sstevel@tonic-gate 116*0Sstevel@tonic-gate$XSUBPP_version = "1.9508"; 117*0Sstevel@tonic-gate 118*0Sstevel@tonic-gatemy ($Is_VMS, $SymSet); 119*0Sstevel@tonic-gateif ($^O eq 'VMS') { 120*0Sstevel@tonic-gate $Is_VMS = 1; 121*0Sstevel@tonic-gate # Establish set of global symbols with max length 28, since xsubpp 122*0Sstevel@tonic-gate # will later add the 'XS_' prefix. 123*0Sstevel@tonic-gate require ExtUtils::XSSymSet; 124*0Sstevel@tonic-gate $SymSet = new ExtUtils::XSSymSet 28; 125*0Sstevel@tonic-gate} 126*0Sstevel@tonic-gate 127*0Sstevel@tonic-gate$FH = 'File0000' ; 128*0Sstevel@tonic-gate 129*0Sstevel@tonic-gate$usage = "Usage: xsubpp [-v] [-C++] [-except] [-prototypes] [-noversioncheck] [-nolinenumbers] [-nooptimize] [-noinout] [-noargtypes] [-s pattern] [-typemap typemap]... file.xs\n"; 130*0Sstevel@tonic-gate 131*0Sstevel@tonic-gate$proto_re = "[" . quotemeta('\$%&*@;[]') . "]" ; 132*0Sstevel@tonic-gate 133*0Sstevel@tonic-gate$except = ""; 134*0Sstevel@tonic-gate$WantPrototypes = -1 ; 135*0Sstevel@tonic-gate$WantVersionChk = 1 ; 136*0Sstevel@tonic-gate$ProtoUsed = 0 ; 137*0Sstevel@tonic-gate$WantLineNumbers = 1 ; 138*0Sstevel@tonic-gate$WantOptimize = 1 ; 139*0Sstevel@tonic-gate$Overload = 0; 140*0Sstevel@tonic-gate$Fallback = 'PL_sv_undef'; 141*0Sstevel@tonic-gate 142*0Sstevel@tonic-gatemy $process_inout = 1; 143*0Sstevel@tonic-gatemy $process_argtypes = 1; 144*0Sstevel@tonic-gate 145*0Sstevel@tonic-gateSWITCH: while (@ARGV and $ARGV[0] =~ /^-./) { 146*0Sstevel@tonic-gate $flag = shift @ARGV; 147*0Sstevel@tonic-gate $flag =~ s/^-// ; 148*0Sstevel@tonic-gate $spat = quotemeta shift, next SWITCH if $flag eq 's'; 149*0Sstevel@tonic-gate $cplusplus = 1, next SWITCH if $flag eq 'C++'; 150*0Sstevel@tonic-gate $hiertype = 1, next SWITCH if $flag eq 'hiertype'; 151*0Sstevel@tonic-gate $WantPrototypes = 0, next SWITCH if $flag eq 'noprototypes'; 152*0Sstevel@tonic-gate $WantPrototypes = 1, next SWITCH if $flag eq 'prototypes'; 153*0Sstevel@tonic-gate $WantVersionChk = 0, next SWITCH if $flag eq 'noversioncheck'; 154*0Sstevel@tonic-gate $WantVersionChk = 1, next SWITCH if $flag eq 'versioncheck'; 155*0Sstevel@tonic-gate # XXX left this in for compat 156*0Sstevel@tonic-gate next SWITCH if $flag eq 'object_capi'; 157*0Sstevel@tonic-gate $except = " TRY", next SWITCH if $flag eq 'except'; 158*0Sstevel@tonic-gate push(@tm,shift), next SWITCH if $flag eq 'typemap'; 159*0Sstevel@tonic-gate $WantLineNumbers = 0, next SWITCH if $flag eq 'nolinenumbers'; 160*0Sstevel@tonic-gate $WantLineNumbers = 1, next SWITCH if $flag eq 'linenumbers'; 161*0Sstevel@tonic-gate $WantOptimize = 0, next SWITCH if $flag eq 'nooptimize'; 162*0Sstevel@tonic-gate $WantOptimize = 1, next SWITCH if $flag eq 'optimize'; 163*0Sstevel@tonic-gate $process_inout = 0, next SWITCH if $flag eq 'noinout'; 164*0Sstevel@tonic-gate $process_inout = 1, next SWITCH if $flag eq 'inout'; 165*0Sstevel@tonic-gate $process_argtypes = 0, next SWITCH if $flag eq 'noargtypes'; 166*0Sstevel@tonic-gate $process_argtypes = 1, next SWITCH if $flag eq 'argtypes'; 167*0Sstevel@tonic-gate (print "xsubpp version $XSUBPP_version\n"), exit 168*0Sstevel@tonic-gate if $flag eq 'v'; 169*0Sstevel@tonic-gate die $usage; 170*0Sstevel@tonic-gate} 171*0Sstevel@tonic-gateif ($WantPrototypes == -1) 172*0Sstevel@tonic-gate { $WantPrototypes = 0} 173*0Sstevel@tonic-gateelse 174*0Sstevel@tonic-gate { $ProtoUsed = 1 } 175*0Sstevel@tonic-gate 176*0Sstevel@tonic-gate 177*0Sstevel@tonic-gate@ARGV == 1 or die $usage; 178*0Sstevel@tonic-gate($dir, $filename) = $ARGV[0] =~ m#(.*)/(.*)# 179*0Sstevel@tonic-gate or ($dir, $filename) = $ARGV[0] =~ m#(.*)\\(.*)# 180*0Sstevel@tonic-gate or ($dir, $filename) = $ARGV[0] =~ m#(.*[>\]])(.*)# 181*0Sstevel@tonic-gate or ($dir, $filename) = ('.', $ARGV[0]); 182*0Sstevel@tonic-gatechdir($dir); 183*0Sstevel@tonic-gate$pwd = cwd(); 184*0Sstevel@tonic-gate 185*0Sstevel@tonic-gate++ $IncludedFiles{$ARGV[0]} ; 186*0Sstevel@tonic-gate 187*0Sstevel@tonic-gatemy(@XSStack) = ({type => 'none'}); # Stack of conditionals and INCLUDEs 188*0Sstevel@tonic-gatemy($XSS_work_idx, $cpp_next_tmp) = (0, "XSubPPtmpAAAA"); 189*0Sstevel@tonic-gate 190*0Sstevel@tonic-gate 191*0Sstevel@tonic-gatesub TrimWhitespace 192*0Sstevel@tonic-gate{ 193*0Sstevel@tonic-gate $_[0] =~ s/^\s+|\s+$//go ; 194*0Sstevel@tonic-gate} 195*0Sstevel@tonic-gate 196*0Sstevel@tonic-gatesub TidyType 197*0Sstevel@tonic-gate{ 198*0Sstevel@tonic-gate local ($_) = @_ ; 199*0Sstevel@tonic-gate 200*0Sstevel@tonic-gate # rationalise any '*' by joining them into bunches and removing whitespace 201*0Sstevel@tonic-gate s#\s*(\*+)\s*#$1#g; 202*0Sstevel@tonic-gate s#(\*+)# $1 #g ; 203*0Sstevel@tonic-gate 204*0Sstevel@tonic-gate # change multiple whitespace into a single space 205*0Sstevel@tonic-gate s/\s+/ /g ; 206*0Sstevel@tonic-gate 207*0Sstevel@tonic-gate # trim leading & trailing whitespace 208*0Sstevel@tonic-gate TrimWhitespace($_) ; 209*0Sstevel@tonic-gate 210*0Sstevel@tonic-gate $_ ; 211*0Sstevel@tonic-gate} 212*0Sstevel@tonic-gate 213*0Sstevel@tonic-gate$typemap = shift @ARGV; 214*0Sstevel@tonic-gateforeach $typemap (@tm) { 215*0Sstevel@tonic-gate die "Can't find $typemap in $pwd\n" unless -r $typemap; 216*0Sstevel@tonic-gate} 217*0Sstevel@tonic-gateunshift @tm, qw(../../../../lib/ExtUtils/typemap ../../../lib/ExtUtils/typemap 218*0Sstevel@tonic-gate ../../lib/ExtUtils/typemap ../../../typemap ../../typemap 219*0Sstevel@tonic-gate ../typemap typemap); 220*0Sstevel@tonic-gateforeach $typemap (@tm) { 221*0Sstevel@tonic-gate next unless -f $typemap ; 222*0Sstevel@tonic-gate # skip directories, binary files etc. 223*0Sstevel@tonic-gate warn("Warning: ignoring non-text typemap file '$typemap'\n"), next 224*0Sstevel@tonic-gate unless -T $typemap ; 225*0Sstevel@tonic-gate open(TYPEMAP, $typemap) 226*0Sstevel@tonic-gate or warn ("Warning: could not open typemap file '$typemap': $!\n"), next; 227*0Sstevel@tonic-gate $mode = 'Typemap'; 228*0Sstevel@tonic-gate $junk = "" ; 229*0Sstevel@tonic-gate $current = \$junk; 230*0Sstevel@tonic-gate while (<TYPEMAP>) { 231*0Sstevel@tonic-gate next if /^\s*#/; 232*0Sstevel@tonic-gate my $line_no = $. + 1; 233*0Sstevel@tonic-gate if (/^INPUT\s*$/) { $mode = 'Input'; $current = \$junk; next; } 234*0Sstevel@tonic-gate if (/^OUTPUT\s*$/) { $mode = 'Output'; $current = \$junk; next; } 235*0Sstevel@tonic-gate if (/^TYPEMAP\s*$/) { $mode = 'Typemap'; $current = \$junk; next; } 236*0Sstevel@tonic-gate if ($mode eq 'Typemap') { 237*0Sstevel@tonic-gate chomp; 238*0Sstevel@tonic-gate my $line = $_ ; 239*0Sstevel@tonic-gate TrimWhitespace($_) ; 240*0Sstevel@tonic-gate # skip blank lines and comment lines 241*0Sstevel@tonic-gate next if /^$/ or /^#/ ; 242*0Sstevel@tonic-gate my($type,$kind, $proto) = /^\s*(.*?\S)\s+(\S+)\s*($proto_re*)\s*$/ or 243*0Sstevel@tonic-gate warn("Warning: File '$typemap' Line $. '$line' TYPEMAP entry needs 2 or 3 columns\n"), next; 244*0Sstevel@tonic-gate $type = TidyType($type) ; 245*0Sstevel@tonic-gate $type_kind{$type} = $kind ; 246*0Sstevel@tonic-gate # prototype defaults to '$' 247*0Sstevel@tonic-gate $proto = "\$" unless $proto ; 248*0Sstevel@tonic-gate warn("Warning: File '$typemap' Line $. '$line' Invalid prototype '$proto'\n") 249*0Sstevel@tonic-gate unless ValidProtoString($proto) ; 250*0Sstevel@tonic-gate $proto_letter{$type} = C_string($proto) ; 251*0Sstevel@tonic-gate } 252*0Sstevel@tonic-gate elsif (/^\s/) { 253*0Sstevel@tonic-gate $$current .= $_; 254*0Sstevel@tonic-gate } 255*0Sstevel@tonic-gate elsif ($mode eq 'Input') { 256*0Sstevel@tonic-gate s/\s+$//; 257*0Sstevel@tonic-gate $input_expr{$_} = ''; 258*0Sstevel@tonic-gate $current = \$input_expr{$_}; 259*0Sstevel@tonic-gate } 260*0Sstevel@tonic-gate else { 261*0Sstevel@tonic-gate s/\s+$//; 262*0Sstevel@tonic-gate $output_expr{$_} = ''; 263*0Sstevel@tonic-gate $current = \$output_expr{$_}; 264*0Sstevel@tonic-gate } 265*0Sstevel@tonic-gate } 266*0Sstevel@tonic-gate close(TYPEMAP); 267*0Sstevel@tonic-gate} 268*0Sstevel@tonic-gate 269*0Sstevel@tonic-gateforeach $key (keys %input_expr) { 270*0Sstevel@tonic-gate $input_expr{$key} =~ s/;*\s+\z//; 271*0Sstevel@tonic-gate} 272*0Sstevel@tonic-gate 273*0Sstevel@tonic-gate$bal = qr[(?:(?>[^()]+)|\((??{ $bal })\))*]; # ()-balanced 274*0Sstevel@tonic-gate$cast = qr[(?:\(\s*SV\s*\*\s*\)\s*)?]; # Optional (SV*) cast 275*0Sstevel@tonic-gate$size = qr[,\s* (??{ $bal }) ]x; # Third arg (to setpvn) 276*0Sstevel@tonic-gate 277*0Sstevel@tonic-gateforeach $key (keys %output_expr) { 278*0Sstevel@tonic-gate use re 'eval'; 279*0Sstevel@tonic-gate 280*0Sstevel@tonic-gate my ($t, $with_size, $arg, $sarg) = 281*0Sstevel@tonic-gate ($output_expr{$key} =~ 282*0Sstevel@tonic-gate m[^ \s+ sv_set ( [iunp] ) v (n)? # Type, is_setpvn 283*0Sstevel@tonic-gate \s* \( \s* $cast \$arg \s* , 284*0Sstevel@tonic-gate \s* ( (??{ $bal }) ) # Set from 285*0Sstevel@tonic-gate ( (??{ $size }) )? # Possible sizeof set-from 286*0Sstevel@tonic-gate \) \s* ; \s* $ 287*0Sstevel@tonic-gate ]x); 288*0Sstevel@tonic-gate $targetable{$key} = [$t, $with_size, $arg, $sarg] if $t; 289*0Sstevel@tonic-gate} 290*0Sstevel@tonic-gate 291*0Sstevel@tonic-gate$END = "!End!\n\n"; # "impossible" keyword (multiple newline) 292*0Sstevel@tonic-gate 293*0Sstevel@tonic-gate# Match an XS keyword 294*0Sstevel@tonic-gate$BLOCK_re= '\s*(' . join('|', qw( 295*0Sstevel@tonic-gate REQUIRE BOOT CASE PREINIT INPUT INIT CODE PPCODE OUTPUT 296*0Sstevel@tonic-gate CLEANUP ALIAS ATTRS PROTOTYPES PROTOTYPE VERSIONCHECK INCLUDE 297*0Sstevel@tonic-gate SCOPE INTERFACE INTERFACE_MACRO C_ARGS POSTCALL OVERLOAD FALLBACK 298*0Sstevel@tonic-gate )) . "|$END)\\s*:"; 299*0Sstevel@tonic-gate 300*0Sstevel@tonic-gate# Input: ($_, @line) == unparsed input. 301*0Sstevel@tonic-gate# Output: ($_, @line) == (rest of line, following lines). 302*0Sstevel@tonic-gate# Return: the matched keyword if found, otherwise 0 303*0Sstevel@tonic-gatesub check_keyword { 304*0Sstevel@tonic-gate $_ = shift(@line) while !/\S/ && @line; 305*0Sstevel@tonic-gate s/^(\s*)($_[0])\s*:\s*(?:#.*)?/$1/s && $2; 306*0Sstevel@tonic-gate} 307*0Sstevel@tonic-gate 308*0Sstevel@tonic-gatemy ($C_group_rex, $C_arg); 309*0Sstevel@tonic-gate# Group in C (no support for comments or literals) 310*0Sstevel@tonic-gate$C_group_rex = qr/ [({\[] 311*0Sstevel@tonic-gate (?: (?> [^()\[\]{}]+ ) | (??{ $C_group_rex }) )* 312*0Sstevel@tonic-gate [)}\]] /x ; 313*0Sstevel@tonic-gate# Chunk in C without comma at toplevel (no comments): 314*0Sstevel@tonic-gate$C_arg = qr/ (?: (?> [^()\[\]{},"']+ ) 315*0Sstevel@tonic-gate | (??{ $C_group_rex }) 316*0Sstevel@tonic-gate | " (?: (?> [^\\"]+ ) 317*0Sstevel@tonic-gate | \\. 318*0Sstevel@tonic-gate )* " # String literal 319*0Sstevel@tonic-gate | ' (?: (?> [^\\']+ ) | \\. )* ' # Char literal 320*0Sstevel@tonic-gate )* /xs; 321*0Sstevel@tonic-gate 322*0Sstevel@tonic-gateif ($WantLineNumbers) { 323*0Sstevel@tonic-gate { 324*0Sstevel@tonic-gate package xsubpp::counter; 325*0Sstevel@tonic-gate sub TIEHANDLE { 326*0Sstevel@tonic-gate my ($class, $cfile) = @_; 327*0Sstevel@tonic-gate my $buf = ""; 328*0Sstevel@tonic-gate $SECTION_END_MARKER = "#line --- \"$cfile\""; 329*0Sstevel@tonic-gate $line_no = 1; 330*0Sstevel@tonic-gate bless \$buf; 331*0Sstevel@tonic-gate } 332*0Sstevel@tonic-gate 333*0Sstevel@tonic-gate sub PRINT { 334*0Sstevel@tonic-gate my $self = shift; 335*0Sstevel@tonic-gate for (@_) { 336*0Sstevel@tonic-gate $$self .= $_; 337*0Sstevel@tonic-gate while ($$self =~ s/^([^\n]*\n)//) { 338*0Sstevel@tonic-gate my $line = $1; 339*0Sstevel@tonic-gate ++ $line_no; 340*0Sstevel@tonic-gate $line =~ s|^\#line\s+---(?=\s)|#line $line_no|; 341*0Sstevel@tonic-gate print STDOUT $line; 342*0Sstevel@tonic-gate } 343*0Sstevel@tonic-gate } 344*0Sstevel@tonic-gate } 345*0Sstevel@tonic-gate 346*0Sstevel@tonic-gate sub PRINTF { 347*0Sstevel@tonic-gate my $self = shift; 348*0Sstevel@tonic-gate my $fmt = shift; 349*0Sstevel@tonic-gate $self->PRINT(sprintf($fmt, @_)); 350*0Sstevel@tonic-gate } 351*0Sstevel@tonic-gate 352*0Sstevel@tonic-gate sub DESTROY { 353*0Sstevel@tonic-gate # Not necessary if we're careful to end with a "\n" 354*0Sstevel@tonic-gate my $self = shift; 355*0Sstevel@tonic-gate print STDOUT $$self; 356*0Sstevel@tonic-gate } 357*0Sstevel@tonic-gate } 358*0Sstevel@tonic-gate 359*0Sstevel@tonic-gate my $cfile = $filename; 360*0Sstevel@tonic-gate $cfile =~ s/\.xs$/.c/i or $cfile .= ".c"; 361*0Sstevel@tonic-gate tie(*PSEUDO_STDOUT, 'xsubpp::counter', $cfile); 362*0Sstevel@tonic-gate select PSEUDO_STDOUT; 363*0Sstevel@tonic-gate} 364*0Sstevel@tonic-gate 365*0Sstevel@tonic-gatesub print_section { 366*0Sstevel@tonic-gate # the "do" is required for right semantics 367*0Sstevel@tonic-gate do { $_ = shift(@line) } while !/\S/ && @line; 368*0Sstevel@tonic-gate 369*0Sstevel@tonic-gate print("#line ", $line_no[@line_no - @line -1], " \"$filename\"\n") 370*0Sstevel@tonic-gate if $WantLineNumbers && !/^\s*#\s*line\b/ && !/^#if XSubPPtmp/; 371*0Sstevel@tonic-gate for (; defined($_) && !/^$BLOCK_re/o; $_ = shift(@line)) { 372*0Sstevel@tonic-gate print "$_\n"; 373*0Sstevel@tonic-gate } 374*0Sstevel@tonic-gate print "$xsubpp::counter::SECTION_END_MARKER\n" if $WantLineNumbers; 375*0Sstevel@tonic-gate} 376*0Sstevel@tonic-gate 377*0Sstevel@tonic-gatesub merge_section { 378*0Sstevel@tonic-gate my $in = ''; 379*0Sstevel@tonic-gate 380*0Sstevel@tonic-gate while (!/\S/ && @line) { 381*0Sstevel@tonic-gate $_ = shift(@line); 382*0Sstevel@tonic-gate } 383*0Sstevel@tonic-gate 384*0Sstevel@tonic-gate for (; defined($_) && !/^$BLOCK_re/o; $_ = shift(@line)) { 385*0Sstevel@tonic-gate $in .= "$_\n"; 386*0Sstevel@tonic-gate } 387*0Sstevel@tonic-gate chomp $in; 388*0Sstevel@tonic-gate return $in; 389*0Sstevel@tonic-gate} 390*0Sstevel@tonic-gate 391*0Sstevel@tonic-gatesub process_keyword($) 392*0Sstevel@tonic-gate{ 393*0Sstevel@tonic-gate my($pattern) = @_ ; 394*0Sstevel@tonic-gate my $kwd ; 395*0Sstevel@tonic-gate 396*0Sstevel@tonic-gate &{"${kwd}_handler"}() 397*0Sstevel@tonic-gate while $kwd = check_keyword($pattern) ; 398*0Sstevel@tonic-gate} 399*0Sstevel@tonic-gate 400*0Sstevel@tonic-gatesub CASE_handler { 401*0Sstevel@tonic-gate blurt ("Error: `CASE:' after unconditional `CASE:'") 402*0Sstevel@tonic-gate if $condnum && $cond eq ''; 403*0Sstevel@tonic-gate $cond = $_; 404*0Sstevel@tonic-gate TrimWhitespace($cond); 405*0Sstevel@tonic-gate print " ", ($condnum++ ? " else" : ""), ($cond ? " if ($cond)\n" : "\n"); 406*0Sstevel@tonic-gate $_ = '' ; 407*0Sstevel@tonic-gate} 408*0Sstevel@tonic-gate 409*0Sstevel@tonic-gatesub INPUT_handler { 410*0Sstevel@tonic-gate for (; !/^$BLOCK_re/o; $_ = shift(@line)) { 411*0Sstevel@tonic-gate last if /^\s*NOT_IMPLEMENTED_YET/; 412*0Sstevel@tonic-gate next unless /\S/; # skip blank lines 413*0Sstevel@tonic-gate 414*0Sstevel@tonic-gate TrimWhitespace($_) ; 415*0Sstevel@tonic-gate my $line = $_ ; 416*0Sstevel@tonic-gate 417*0Sstevel@tonic-gate # remove trailing semicolon if no initialisation 418*0Sstevel@tonic-gate s/\s*;$//g unless /[=;+].*\S/ ; 419*0Sstevel@tonic-gate 420*0Sstevel@tonic-gate # Process the length(foo) declarations 421*0Sstevel@tonic-gate if (s/^([^=]*)\blength\(\s*(\w+)\s*\)\s*$/$1 XSauto_length_of_$2=NO_INIT/x) { 422*0Sstevel@tonic-gate print "\tSTRLEN\tSTRLEN_length_of_$2;\n"; 423*0Sstevel@tonic-gate $lengthof{$2} = $name; 424*0Sstevel@tonic-gate # $islengthof{$name} = $1; 425*0Sstevel@tonic-gate $deferred .= "\n\tXSauto_length_of_$2 = STRLEN_length_of_$2;"; 426*0Sstevel@tonic-gate } 427*0Sstevel@tonic-gate 428*0Sstevel@tonic-gate # check for optional initialisation code 429*0Sstevel@tonic-gate my $var_init = '' ; 430*0Sstevel@tonic-gate $var_init = $1 if s/\s*([=;+].*)$//s ; 431*0Sstevel@tonic-gate $var_init =~ s/"/\\"/g; 432*0Sstevel@tonic-gate 433*0Sstevel@tonic-gate s/\s+/ /g; 434*0Sstevel@tonic-gate my ($var_type, $var_addr, $var_name) = /^(.*?[^&\s])\s*(\&?)\s*\b(\w+)$/s 435*0Sstevel@tonic-gate or blurt("Error: invalid argument declaration '$line'"), next; 436*0Sstevel@tonic-gate 437*0Sstevel@tonic-gate # Check for duplicate definitions 438*0Sstevel@tonic-gate blurt ("Error: duplicate definition of argument '$var_name' ignored"), next 439*0Sstevel@tonic-gate if $arg_list{$var_name}++ 440*0Sstevel@tonic-gate or defined $argtype_seen{$var_name} and not $processing_arg_with_types; 441*0Sstevel@tonic-gate 442*0Sstevel@tonic-gate $thisdone |= $var_name eq "THIS"; 443*0Sstevel@tonic-gate $retvaldone |= $var_name eq "RETVAL"; 444*0Sstevel@tonic-gate $var_types{$var_name} = $var_type; 445*0Sstevel@tonic-gate # XXXX This check is a safeguard against the unfinished conversion of 446*0Sstevel@tonic-gate # generate_init(). When generate_init() is fixed, 447*0Sstevel@tonic-gate # one can use 2-args map_type() unconditionally. 448*0Sstevel@tonic-gate if ($var_type =~ / \( \s* \* \s* \) /x) { 449*0Sstevel@tonic-gate # Function pointers are not yet supported with &output_init! 450*0Sstevel@tonic-gate print "\t" . &map_type($var_type, $var_name); 451*0Sstevel@tonic-gate $name_printed = 1; 452*0Sstevel@tonic-gate } else { 453*0Sstevel@tonic-gate print "\t" . &map_type($var_type); 454*0Sstevel@tonic-gate $name_printed = 0; 455*0Sstevel@tonic-gate } 456*0Sstevel@tonic-gate $var_num = $args_match{$var_name}; 457*0Sstevel@tonic-gate 458*0Sstevel@tonic-gate $proto_arg[$var_num] = ProtoString($var_type) 459*0Sstevel@tonic-gate if $var_num ; 460*0Sstevel@tonic-gate $func_args =~ s/\b($var_name)\b/&$1/ if $var_addr; 461*0Sstevel@tonic-gate if ($var_init =~ /^[=;]\s*NO_INIT\s*;?\s*$/ 462*0Sstevel@tonic-gate or $in_out{$var_name} and $in_out{$var_name} =~ /^OUT/ 463*0Sstevel@tonic-gate and $var_init !~ /\S/) { 464*0Sstevel@tonic-gate if ($name_printed) { 465*0Sstevel@tonic-gate print ";\n"; 466*0Sstevel@tonic-gate } else { 467*0Sstevel@tonic-gate print "\t$var_name;\n"; 468*0Sstevel@tonic-gate } 469*0Sstevel@tonic-gate } elsif ($var_init =~ /\S/) { 470*0Sstevel@tonic-gate &output_init($var_type, $var_num, $var_name, $var_init, $name_printed); 471*0Sstevel@tonic-gate } elsif ($var_num) { 472*0Sstevel@tonic-gate # generate initialization code 473*0Sstevel@tonic-gate &generate_init($var_type, $var_num, $var_name, $name_printed); 474*0Sstevel@tonic-gate } else { 475*0Sstevel@tonic-gate print ";\n"; 476*0Sstevel@tonic-gate } 477*0Sstevel@tonic-gate } 478*0Sstevel@tonic-gate} 479*0Sstevel@tonic-gate 480*0Sstevel@tonic-gatesub OUTPUT_handler { 481*0Sstevel@tonic-gate for (; !/^$BLOCK_re/o; $_ = shift(@line)) { 482*0Sstevel@tonic-gate next unless /\S/; 483*0Sstevel@tonic-gate if (/^\s*SETMAGIC\s*:\s*(ENABLE|DISABLE)\s*/) { 484*0Sstevel@tonic-gate $DoSetMagic = ($1 eq "ENABLE" ? 1 : 0); 485*0Sstevel@tonic-gate next; 486*0Sstevel@tonic-gate } 487*0Sstevel@tonic-gate my ($outarg, $outcode) = /^\s*(\S+)\s*(.*?)\s*$/s ; 488*0Sstevel@tonic-gate blurt ("Error: duplicate OUTPUT argument '$outarg' ignored"), next 489*0Sstevel@tonic-gate if $outargs{$outarg} ++ ; 490*0Sstevel@tonic-gate if (!$gotRETVAL and $outarg eq 'RETVAL') { 491*0Sstevel@tonic-gate # deal with RETVAL last 492*0Sstevel@tonic-gate $RETVAL_code = $outcode ; 493*0Sstevel@tonic-gate $gotRETVAL = 1 ; 494*0Sstevel@tonic-gate next ; 495*0Sstevel@tonic-gate } 496*0Sstevel@tonic-gate blurt ("Error: OUTPUT $outarg not an argument"), next 497*0Sstevel@tonic-gate unless defined($args_match{$outarg}); 498*0Sstevel@tonic-gate blurt("Error: No input definition for OUTPUT argument '$outarg' - ignored"), next 499*0Sstevel@tonic-gate unless defined $var_types{$outarg} ; 500*0Sstevel@tonic-gate $var_num = $args_match{$outarg}; 501*0Sstevel@tonic-gate if ($outcode) { 502*0Sstevel@tonic-gate print "\t$outcode\n"; 503*0Sstevel@tonic-gate print "\tSvSETMAGIC(ST(" , $var_num-1 , "));\n" if $DoSetMagic; 504*0Sstevel@tonic-gate } else { 505*0Sstevel@tonic-gate &generate_output($var_types{$outarg}, $var_num, $outarg, $DoSetMagic); 506*0Sstevel@tonic-gate } 507*0Sstevel@tonic-gate delete $in_out{$outarg} # No need to auto-OUTPUT 508*0Sstevel@tonic-gate if exists $in_out{$outarg} and $in_out{$outarg} =~ /OUT$/; 509*0Sstevel@tonic-gate } 510*0Sstevel@tonic-gate} 511*0Sstevel@tonic-gate 512*0Sstevel@tonic-gatesub C_ARGS_handler() { 513*0Sstevel@tonic-gate my $in = merge_section(); 514*0Sstevel@tonic-gate 515*0Sstevel@tonic-gate TrimWhitespace($in); 516*0Sstevel@tonic-gate $func_args = $in; 517*0Sstevel@tonic-gate} 518*0Sstevel@tonic-gate 519*0Sstevel@tonic-gatesub INTERFACE_MACRO_handler() { 520*0Sstevel@tonic-gate my $in = merge_section(); 521*0Sstevel@tonic-gate 522*0Sstevel@tonic-gate TrimWhitespace($in); 523*0Sstevel@tonic-gate if ($in =~ /\s/) { # two 524*0Sstevel@tonic-gate ($interface_macro, $interface_macro_set) = split ' ', $in; 525*0Sstevel@tonic-gate } else { 526*0Sstevel@tonic-gate $interface_macro = $in; 527*0Sstevel@tonic-gate $interface_macro_set = 'UNKNOWN_CVT'; # catch later 528*0Sstevel@tonic-gate } 529*0Sstevel@tonic-gate $interface = 1; # local 530*0Sstevel@tonic-gate $Interfaces = 1; # global 531*0Sstevel@tonic-gate} 532*0Sstevel@tonic-gate 533*0Sstevel@tonic-gatesub INTERFACE_handler() { 534*0Sstevel@tonic-gate my $in = merge_section(); 535*0Sstevel@tonic-gate 536*0Sstevel@tonic-gate TrimWhitespace($in); 537*0Sstevel@tonic-gate 538*0Sstevel@tonic-gate foreach (split /[\s,]+/, $in) { 539*0Sstevel@tonic-gate $Interfaces{$_} = $_; 540*0Sstevel@tonic-gate } 541*0Sstevel@tonic-gate print Q<<"EOF"; 542*0Sstevel@tonic-gate# XSFUNCTION = $interface_macro($ret_type,cv,XSANY.any_dptr); 543*0Sstevel@tonic-gateEOF 544*0Sstevel@tonic-gate $interface = 1; # local 545*0Sstevel@tonic-gate $Interfaces = 1; # global 546*0Sstevel@tonic-gate} 547*0Sstevel@tonic-gate 548*0Sstevel@tonic-gatesub CLEANUP_handler() { print_section() } 549*0Sstevel@tonic-gatesub PREINIT_handler() { print_section() } 550*0Sstevel@tonic-gatesub POSTCALL_handler() { print_section() } 551*0Sstevel@tonic-gatesub INIT_handler() { print_section() } 552*0Sstevel@tonic-gate 553*0Sstevel@tonic-gatesub GetAliases 554*0Sstevel@tonic-gate{ 555*0Sstevel@tonic-gate my ($line) = @_ ; 556*0Sstevel@tonic-gate my ($orig) = $line ; 557*0Sstevel@tonic-gate my ($alias) ; 558*0Sstevel@tonic-gate my ($value) ; 559*0Sstevel@tonic-gate 560*0Sstevel@tonic-gate # Parse alias definitions 561*0Sstevel@tonic-gate # format is 562*0Sstevel@tonic-gate # alias = value alias = value ... 563*0Sstevel@tonic-gate 564*0Sstevel@tonic-gate while ($line =~ s/^\s*([\w:]+)\s*=\s*(\w+)\s*//) { 565*0Sstevel@tonic-gate $alias = $1 ; 566*0Sstevel@tonic-gate $orig_alias = $alias ; 567*0Sstevel@tonic-gate $value = $2 ; 568*0Sstevel@tonic-gate 569*0Sstevel@tonic-gate # check for optional package definition in the alias 570*0Sstevel@tonic-gate $alias = $Packprefix . $alias if $alias !~ /::/ ; 571*0Sstevel@tonic-gate 572*0Sstevel@tonic-gate # check for duplicate alias name & duplicate value 573*0Sstevel@tonic-gate Warn("Warning: Ignoring duplicate alias '$orig_alias'") 574*0Sstevel@tonic-gate if defined $XsubAliases{$alias} ; 575*0Sstevel@tonic-gate 576*0Sstevel@tonic-gate Warn("Warning: Aliases '$orig_alias' and '$XsubAliasValues{$value}' have identical values") 577*0Sstevel@tonic-gate if $XsubAliasValues{$value} ; 578*0Sstevel@tonic-gate 579*0Sstevel@tonic-gate $XsubAliases = 1; 580*0Sstevel@tonic-gate $XsubAliases{$alias} = $value ; 581*0Sstevel@tonic-gate $XsubAliasValues{$value} = $orig_alias ; 582*0Sstevel@tonic-gate } 583*0Sstevel@tonic-gate 584*0Sstevel@tonic-gate blurt("Error: Cannot parse ALIAS definitions from '$orig'") 585*0Sstevel@tonic-gate if $line ; 586*0Sstevel@tonic-gate} 587*0Sstevel@tonic-gate 588*0Sstevel@tonic-gatesub ATTRS_handler () 589*0Sstevel@tonic-gate{ 590*0Sstevel@tonic-gate for (; !/^$BLOCK_re/o; $_ = shift(@line)) { 591*0Sstevel@tonic-gate next unless /\S/; 592*0Sstevel@tonic-gate TrimWhitespace($_) ; 593*0Sstevel@tonic-gate push @Attributes, $_; 594*0Sstevel@tonic-gate } 595*0Sstevel@tonic-gate} 596*0Sstevel@tonic-gate 597*0Sstevel@tonic-gatesub ALIAS_handler () 598*0Sstevel@tonic-gate{ 599*0Sstevel@tonic-gate for (; !/^$BLOCK_re/o; $_ = shift(@line)) { 600*0Sstevel@tonic-gate next unless /\S/; 601*0Sstevel@tonic-gate TrimWhitespace($_) ; 602*0Sstevel@tonic-gate GetAliases($_) if $_ ; 603*0Sstevel@tonic-gate } 604*0Sstevel@tonic-gate} 605*0Sstevel@tonic-gate 606*0Sstevel@tonic-gatesub OVERLOAD_handler() 607*0Sstevel@tonic-gate{ 608*0Sstevel@tonic-gate for (; !/^$BLOCK_re/o; $_ = shift(@line)) { 609*0Sstevel@tonic-gate next unless /\S/; 610*0Sstevel@tonic-gate TrimWhitespace($_) ; 611*0Sstevel@tonic-gate while ( s/^\s*([\w:"\\)\+\-\*\/\%\<\>\.\&\|\^\!\~\{\}\=]+)\s*//) { 612*0Sstevel@tonic-gate $Overload = 1 unless $Overload; 613*0Sstevel@tonic-gate my $overload = "$Package\::(".$1 ; 614*0Sstevel@tonic-gate push(@InitFileCode, 615*0Sstevel@tonic-gate " newXS(\"$overload\", XS_$Full_func_name, file$proto);\n"); 616*0Sstevel@tonic-gate } 617*0Sstevel@tonic-gate } 618*0Sstevel@tonic-gate 619*0Sstevel@tonic-gate} 620*0Sstevel@tonic-gate 621*0Sstevel@tonic-gatesub FALLBACK_handler() 622*0Sstevel@tonic-gate{ 623*0Sstevel@tonic-gate # the rest of the current line should contain either TRUE, 624*0Sstevel@tonic-gate # FALSE or UNDEF 625*0Sstevel@tonic-gate 626*0Sstevel@tonic-gate TrimWhitespace($_) ; 627*0Sstevel@tonic-gate my %map = ( 628*0Sstevel@tonic-gate TRUE => "PL_sv_yes", 1 => "PL_sv_yes", 629*0Sstevel@tonic-gate FALSE => "PL_sv_no", 0 => "PL_sv_no", 630*0Sstevel@tonic-gate UNDEF => "PL_sv_undef", 631*0Sstevel@tonic-gate ) ; 632*0Sstevel@tonic-gate 633*0Sstevel@tonic-gate # check for valid FALLBACK value 634*0Sstevel@tonic-gate death ("Error: FALLBACK: TRUE/FALSE/UNDEF") unless exists $map{uc $_} ; 635*0Sstevel@tonic-gate 636*0Sstevel@tonic-gate $Fallback = $map{uc $_} ; 637*0Sstevel@tonic-gate} 638*0Sstevel@tonic-gate 639*0Sstevel@tonic-gatesub REQUIRE_handler () 640*0Sstevel@tonic-gate{ 641*0Sstevel@tonic-gate # the rest of the current line should contain a version number 642*0Sstevel@tonic-gate my ($Ver) = $_ ; 643*0Sstevel@tonic-gate 644*0Sstevel@tonic-gate TrimWhitespace($Ver) ; 645*0Sstevel@tonic-gate 646*0Sstevel@tonic-gate death ("Error: REQUIRE expects a version number") 647*0Sstevel@tonic-gate unless $Ver ; 648*0Sstevel@tonic-gate 649*0Sstevel@tonic-gate # check that the version number is of the form n.n 650*0Sstevel@tonic-gate death ("Error: REQUIRE: expected a number, got '$Ver'") 651*0Sstevel@tonic-gate unless $Ver =~ /^\d+(\.\d*)?/ ; 652*0Sstevel@tonic-gate 653*0Sstevel@tonic-gate death ("Error: xsubpp $Ver (or better) required--this is only $XSUBPP_version.") 654*0Sstevel@tonic-gate unless $XSUBPP_version >= $Ver ; 655*0Sstevel@tonic-gate} 656*0Sstevel@tonic-gate 657*0Sstevel@tonic-gatesub VERSIONCHECK_handler () 658*0Sstevel@tonic-gate{ 659*0Sstevel@tonic-gate # the rest of the current line should contain either ENABLE or 660*0Sstevel@tonic-gate # DISABLE 661*0Sstevel@tonic-gate 662*0Sstevel@tonic-gate TrimWhitespace($_) ; 663*0Sstevel@tonic-gate 664*0Sstevel@tonic-gate # check for ENABLE/DISABLE 665*0Sstevel@tonic-gate death ("Error: VERSIONCHECK: ENABLE/DISABLE") 666*0Sstevel@tonic-gate unless /^(ENABLE|DISABLE)/i ; 667*0Sstevel@tonic-gate 668*0Sstevel@tonic-gate $WantVersionChk = 1 if $1 eq 'ENABLE' ; 669*0Sstevel@tonic-gate $WantVersionChk = 0 if $1 eq 'DISABLE' ; 670*0Sstevel@tonic-gate 671*0Sstevel@tonic-gate} 672*0Sstevel@tonic-gate 673*0Sstevel@tonic-gatesub PROTOTYPE_handler () 674*0Sstevel@tonic-gate{ 675*0Sstevel@tonic-gate my $specified ; 676*0Sstevel@tonic-gate 677*0Sstevel@tonic-gate death("Error: Only 1 PROTOTYPE definition allowed per xsub") 678*0Sstevel@tonic-gate if $proto_in_this_xsub ++ ; 679*0Sstevel@tonic-gate 680*0Sstevel@tonic-gate for (; !/^$BLOCK_re/o; $_ = shift(@line)) { 681*0Sstevel@tonic-gate next unless /\S/; 682*0Sstevel@tonic-gate $specified = 1 ; 683*0Sstevel@tonic-gate TrimWhitespace($_) ; 684*0Sstevel@tonic-gate if ($_ eq 'DISABLE') { 685*0Sstevel@tonic-gate $ProtoThisXSUB = 0 686*0Sstevel@tonic-gate } 687*0Sstevel@tonic-gate elsif ($_ eq 'ENABLE') { 688*0Sstevel@tonic-gate $ProtoThisXSUB = 1 689*0Sstevel@tonic-gate } 690*0Sstevel@tonic-gate else { 691*0Sstevel@tonic-gate # remove any whitespace 692*0Sstevel@tonic-gate s/\s+//g ; 693*0Sstevel@tonic-gate death("Error: Invalid prototype '$_'") 694*0Sstevel@tonic-gate unless ValidProtoString($_) ; 695*0Sstevel@tonic-gate $ProtoThisXSUB = C_string($_) ; 696*0Sstevel@tonic-gate } 697*0Sstevel@tonic-gate } 698*0Sstevel@tonic-gate 699*0Sstevel@tonic-gate # If no prototype specified, then assume empty prototype "" 700*0Sstevel@tonic-gate $ProtoThisXSUB = 2 unless $specified ; 701*0Sstevel@tonic-gate 702*0Sstevel@tonic-gate $ProtoUsed = 1 ; 703*0Sstevel@tonic-gate 704*0Sstevel@tonic-gate} 705*0Sstevel@tonic-gate 706*0Sstevel@tonic-gatesub SCOPE_handler () 707*0Sstevel@tonic-gate{ 708*0Sstevel@tonic-gate death("Error: Only 1 SCOPE declaration allowed per xsub") 709*0Sstevel@tonic-gate if $scope_in_this_xsub ++ ; 710*0Sstevel@tonic-gate 711*0Sstevel@tonic-gate for (; !/^$BLOCK_re/o; $_ = shift(@line)) { 712*0Sstevel@tonic-gate next unless /\S/; 713*0Sstevel@tonic-gate TrimWhitespace($_) ; 714*0Sstevel@tonic-gate if ($_ =~ /^DISABLE/i) { 715*0Sstevel@tonic-gate $ScopeThisXSUB = 0 716*0Sstevel@tonic-gate } 717*0Sstevel@tonic-gate elsif ($_ =~ /^ENABLE/i) { 718*0Sstevel@tonic-gate $ScopeThisXSUB = 1 719*0Sstevel@tonic-gate } 720*0Sstevel@tonic-gate } 721*0Sstevel@tonic-gate 722*0Sstevel@tonic-gate} 723*0Sstevel@tonic-gate 724*0Sstevel@tonic-gatesub PROTOTYPES_handler () 725*0Sstevel@tonic-gate{ 726*0Sstevel@tonic-gate # the rest of the current line should contain either ENABLE or 727*0Sstevel@tonic-gate # DISABLE 728*0Sstevel@tonic-gate 729*0Sstevel@tonic-gate TrimWhitespace($_) ; 730*0Sstevel@tonic-gate 731*0Sstevel@tonic-gate # check for ENABLE/DISABLE 732*0Sstevel@tonic-gate death ("Error: PROTOTYPES: ENABLE/DISABLE") 733*0Sstevel@tonic-gate unless /^(ENABLE|DISABLE)/i ; 734*0Sstevel@tonic-gate 735*0Sstevel@tonic-gate $WantPrototypes = 1 if $1 eq 'ENABLE' ; 736*0Sstevel@tonic-gate $WantPrototypes = 0 if $1 eq 'DISABLE' ; 737*0Sstevel@tonic-gate $ProtoUsed = 1 ; 738*0Sstevel@tonic-gate 739*0Sstevel@tonic-gate} 740*0Sstevel@tonic-gate 741*0Sstevel@tonic-gatesub INCLUDE_handler () 742*0Sstevel@tonic-gate{ 743*0Sstevel@tonic-gate # the rest of the current line should contain a valid filename 744*0Sstevel@tonic-gate 745*0Sstevel@tonic-gate TrimWhitespace($_) ; 746*0Sstevel@tonic-gate 747*0Sstevel@tonic-gate death("INCLUDE: filename missing") 748*0Sstevel@tonic-gate unless $_ ; 749*0Sstevel@tonic-gate 750*0Sstevel@tonic-gate death("INCLUDE: output pipe is illegal") 751*0Sstevel@tonic-gate if /^\s*\|/ ; 752*0Sstevel@tonic-gate 753*0Sstevel@tonic-gate # simple minded recursion detector 754*0Sstevel@tonic-gate death("INCLUDE loop detected") 755*0Sstevel@tonic-gate if $IncludedFiles{$_} ; 756*0Sstevel@tonic-gate 757*0Sstevel@tonic-gate ++ $IncludedFiles{$_} unless /\|\s*$/ ; 758*0Sstevel@tonic-gate 759*0Sstevel@tonic-gate # Save the current file context. 760*0Sstevel@tonic-gate push(@XSStack, { 761*0Sstevel@tonic-gate type => 'file', 762*0Sstevel@tonic-gate LastLine => $lastline, 763*0Sstevel@tonic-gate LastLineNo => $lastline_no, 764*0Sstevel@tonic-gate Line => \@line, 765*0Sstevel@tonic-gate LineNo => \@line_no, 766*0Sstevel@tonic-gate Filename => $filename, 767*0Sstevel@tonic-gate Handle => $FH, 768*0Sstevel@tonic-gate }) ; 769*0Sstevel@tonic-gate 770*0Sstevel@tonic-gate ++ $FH ; 771*0Sstevel@tonic-gate 772*0Sstevel@tonic-gate # open the new file 773*0Sstevel@tonic-gate open ($FH, "$_") or death("Cannot open '$_': $!") ; 774*0Sstevel@tonic-gate 775*0Sstevel@tonic-gate print Q<<"EOF" ; 776*0Sstevel@tonic-gate# 777*0Sstevel@tonic-gate#/* INCLUDE: Including '$_' from '$filename' */ 778*0Sstevel@tonic-gate# 779*0Sstevel@tonic-gateEOF 780*0Sstevel@tonic-gate 781*0Sstevel@tonic-gate $filename = $_ ; 782*0Sstevel@tonic-gate 783*0Sstevel@tonic-gate # Prime the pump by reading the first 784*0Sstevel@tonic-gate # non-blank line 785*0Sstevel@tonic-gate 786*0Sstevel@tonic-gate # skip leading blank lines 787*0Sstevel@tonic-gate while (<$FH>) { 788*0Sstevel@tonic-gate last unless /^\s*$/ ; 789*0Sstevel@tonic-gate } 790*0Sstevel@tonic-gate 791*0Sstevel@tonic-gate $lastline = $_ ; 792*0Sstevel@tonic-gate $lastline_no = $. ; 793*0Sstevel@tonic-gate 794*0Sstevel@tonic-gate} 795*0Sstevel@tonic-gate 796*0Sstevel@tonic-gatesub PopFile() 797*0Sstevel@tonic-gate{ 798*0Sstevel@tonic-gate return 0 unless $XSStack[-1]{type} eq 'file' ; 799*0Sstevel@tonic-gate 800*0Sstevel@tonic-gate my $data = pop @XSStack ; 801*0Sstevel@tonic-gate my $ThisFile = $filename ; 802*0Sstevel@tonic-gate my $isPipe = ($filename =~ /\|\s*$/) ; 803*0Sstevel@tonic-gate 804*0Sstevel@tonic-gate -- $IncludedFiles{$filename} 805*0Sstevel@tonic-gate unless $isPipe ; 806*0Sstevel@tonic-gate 807*0Sstevel@tonic-gate close $FH ; 808*0Sstevel@tonic-gate 809*0Sstevel@tonic-gate $FH = $data->{Handle} ; 810*0Sstevel@tonic-gate $filename = $data->{Filename} ; 811*0Sstevel@tonic-gate $lastline = $data->{LastLine} ; 812*0Sstevel@tonic-gate $lastline_no = $data->{LastLineNo} ; 813*0Sstevel@tonic-gate @line = @{ $data->{Line} } ; 814*0Sstevel@tonic-gate @line_no = @{ $data->{LineNo} } ; 815*0Sstevel@tonic-gate 816*0Sstevel@tonic-gate if ($isPipe and $? ) { 817*0Sstevel@tonic-gate -- $lastline_no ; 818*0Sstevel@tonic-gate print STDERR "Error reading from pipe '$ThisFile': $! in $filename, line $lastline_no\n" ; 819*0Sstevel@tonic-gate exit 1 ; 820*0Sstevel@tonic-gate } 821*0Sstevel@tonic-gate 822*0Sstevel@tonic-gate print Q<<"EOF" ; 823*0Sstevel@tonic-gate# 824*0Sstevel@tonic-gate#/* INCLUDE: Returning to '$filename' from '$ThisFile' */ 825*0Sstevel@tonic-gate# 826*0Sstevel@tonic-gateEOF 827*0Sstevel@tonic-gate 828*0Sstevel@tonic-gate return 1 ; 829*0Sstevel@tonic-gate} 830*0Sstevel@tonic-gate 831*0Sstevel@tonic-gatesub ValidProtoString ($) 832*0Sstevel@tonic-gate{ 833*0Sstevel@tonic-gate my($string) = @_ ; 834*0Sstevel@tonic-gate 835*0Sstevel@tonic-gate if ( $string =~ /^$proto_re+$/ ) { 836*0Sstevel@tonic-gate return $string ; 837*0Sstevel@tonic-gate } 838*0Sstevel@tonic-gate 839*0Sstevel@tonic-gate return 0 ; 840*0Sstevel@tonic-gate} 841*0Sstevel@tonic-gate 842*0Sstevel@tonic-gatesub C_string ($) 843*0Sstevel@tonic-gate{ 844*0Sstevel@tonic-gate my($string) = @_ ; 845*0Sstevel@tonic-gate 846*0Sstevel@tonic-gate $string =~ s[\\][\\\\]g ; 847*0Sstevel@tonic-gate $string ; 848*0Sstevel@tonic-gate} 849*0Sstevel@tonic-gate 850*0Sstevel@tonic-gatesub ProtoString ($) 851*0Sstevel@tonic-gate{ 852*0Sstevel@tonic-gate my ($type) = @_ ; 853*0Sstevel@tonic-gate 854*0Sstevel@tonic-gate $proto_letter{$type} or "\$" ; 855*0Sstevel@tonic-gate} 856*0Sstevel@tonic-gate 857*0Sstevel@tonic-gatesub check_cpp { 858*0Sstevel@tonic-gate my @cpp = grep(/^\#\s*(?:if|e\w+)/, @line); 859*0Sstevel@tonic-gate if (@cpp) { 860*0Sstevel@tonic-gate my ($cpp, $cpplevel); 861*0Sstevel@tonic-gate for $cpp (@cpp) { 862*0Sstevel@tonic-gate if ($cpp =~ /^\#\s*if/) { 863*0Sstevel@tonic-gate $cpplevel++; 864*0Sstevel@tonic-gate } elsif (!$cpplevel) { 865*0Sstevel@tonic-gate Warn("Warning: #else/elif/endif without #if in this function"); 866*0Sstevel@tonic-gate print STDERR " (precede it with a blank line if the matching #if is outside the function)\n" 867*0Sstevel@tonic-gate if $XSStack[-1]{type} eq 'if'; 868*0Sstevel@tonic-gate return; 869*0Sstevel@tonic-gate } elsif ($cpp =~ /^\#\s*endif/) { 870*0Sstevel@tonic-gate $cpplevel--; 871*0Sstevel@tonic-gate } 872*0Sstevel@tonic-gate } 873*0Sstevel@tonic-gate Warn("Warning: #if without #endif in this function") if $cpplevel; 874*0Sstevel@tonic-gate } 875*0Sstevel@tonic-gate} 876*0Sstevel@tonic-gate 877*0Sstevel@tonic-gate 878*0Sstevel@tonic-gatesub Q { 879*0Sstevel@tonic-gate my($text) = @_; 880*0Sstevel@tonic-gate $text =~ s/^#//gm; 881*0Sstevel@tonic-gate $text =~ s/\[\[/{/g; 882*0Sstevel@tonic-gate $text =~ s/\]\]/}/g; 883*0Sstevel@tonic-gate $text; 884*0Sstevel@tonic-gate} 885*0Sstevel@tonic-gate 886*0Sstevel@tonic-gateopen($FH, $filename) or die "cannot open $filename: $!\n"; 887*0Sstevel@tonic-gate 888*0Sstevel@tonic-gate# Identify the version of xsubpp used 889*0Sstevel@tonic-gateprint <<EOM ; 890*0Sstevel@tonic-gate/* 891*0Sstevel@tonic-gate * This file was generated automatically by xsubpp version $XSUBPP_version from the 892*0Sstevel@tonic-gate * contents of $filename. Do not edit this file, edit $filename instead. 893*0Sstevel@tonic-gate * 894*0Sstevel@tonic-gate * ANY CHANGES MADE HERE WILL BE LOST! 895*0Sstevel@tonic-gate * 896*0Sstevel@tonic-gate */ 897*0Sstevel@tonic-gate 898*0Sstevel@tonic-gateEOM 899*0Sstevel@tonic-gate 900*0Sstevel@tonic-gate 901*0Sstevel@tonic-gateprint("#line 1 \"$filename\"\n") 902*0Sstevel@tonic-gate if $WantLineNumbers; 903*0Sstevel@tonic-gate 904*0Sstevel@tonic-gatefirstmodule: 905*0Sstevel@tonic-gatewhile (<$FH>) { 906*0Sstevel@tonic-gate if (/^=/) { 907*0Sstevel@tonic-gate my $podstartline = $.; 908*0Sstevel@tonic-gate do { 909*0Sstevel@tonic-gate if (/^=cut\s*$/) { 910*0Sstevel@tonic-gate # We can't just write out a /* */ comment, as our embedded 911*0Sstevel@tonic-gate # POD might itself be in a comment. We can't put a /**/ 912*0Sstevel@tonic-gate # comment inside #if 0, as the C standard says that the source 913*0Sstevel@tonic-gate # file is decomposed into preprocessing characters in the stage 914*0Sstevel@tonic-gate # before preprocessing commands are executed. 915*0Sstevel@tonic-gate # I don't want to leave the text as barewords, because the spec 916*0Sstevel@tonic-gate # isn't clear whether macros are expanded before or after 917*0Sstevel@tonic-gate # preprocessing commands are executed, and someone pathological 918*0Sstevel@tonic-gate # may just have defined one of the 3 words as a macro that does 919*0Sstevel@tonic-gate # something strange. Multiline strings are illegal in C, so 920*0Sstevel@tonic-gate # the "" we write must be a string literal. And they aren't 921*0Sstevel@tonic-gate # concatenated until 2 steps later, so we are safe. 922*0Sstevel@tonic-gate print("#if 0\n \"Skipped embedded POD.\"\n#endif\n"); 923*0Sstevel@tonic-gate printf("#line %d \"$filename\"\n", $. + 1) 924*0Sstevel@tonic-gate if $WantLineNumbers; 925*0Sstevel@tonic-gate next firstmodule 926*0Sstevel@tonic-gate } 927*0Sstevel@tonic-gate 928*0Sstevel@tonic-gate } while (<$FH>); 929*0Sstevel@tonic-gate # At this point $. is at end of file so die won't state the start 930*0Sstevel@tonic-gate # of the problem, and as we haven't yet read any lines &death won't 931*0Sstevel@tonic-gate # show the correct line in the message either. 932*0Sstevel@tonic-gate die ("Error: Unterminated pod in $filename, line $podstartline\n") 933*0Sstevel@tonic-gate unless $lastline; 934*0Sstevel@tonic-gate } 935*0Sstevel@tonic-gate last if ($Module, $Package, $Prefix) = 936*0Sstevel@tonic-gate /^MODULE\s*=\s*([\w:]+)(?:\s+PACKAGE\s*=\s*([\w:]+))?(?:\s+PREFIX\s*=\s*(\S+))?\s*$/; 937*0Sstevel@tonic-gate 938*0Sstevel@tonic-gate print $_; 939*0Sstevel@tonic-gate} 940*0Sstevel@tonic-gate&Exit unless defined $_; 941*0Sstevel@tonic-gate 942*0Sstevel@tonic-gateprint "$xsubpp::counter::SECTION_END_MARKER\n" if $WantLineNumbers; 943*0Sstevel@tonic-gate 944*0Sstevel@tonic-gate$lastline = $_; 945*0Sstevel@tonic-gate$lastline_no = $.; 946*0Sstevel@tonic-gate 947*0Sstevel@tonic-gate# Read next xsub into @line from ($lastline, <$FH>). 948*0Sstevel@tonic-gatesub fetch_para { 949*0Sstevel@tonic-gate # parse paragraph 950*0Sstevel@tonic-gate death ("Error: Unterminated `#if/#ifdef/#ifndef'") 951*0Sstevel@tonic-gate if !defined $lastline && $XSStack[-1]{type} eq 'if'; 952*0Sstevel@tonic-gate @line = (); 953*0Sstevel@tonic-gate @line_no = () ; 954*0Sstevel@tonic-gate return PopFile() if !defined $lastline; 955*0Sstevel@tonic-gate 956*0Sstevel@tonic-gate if ($lastline =~ 957*0Sstevel@tonic-gate /^MODULE\s*=\s*([\w:]+)(?:\s+PACKAGE\s*=\s*([\w:]+))?(?:\s+PREFIX\s*=\s*(\S+))?\s*$/) { 958*0Sstevel@tonic-gate $Module = $1; 959*0Sstevel@tonic-gate $Package = defined($2) ? $2 : ''; # keep -w happy 960*0Sstevel@tonic-gate $Prefix = defined($3) ? $3 : ''; # keep -w happy 961*0Sstevel@tonic-gate $Prefix = quotemeta $Prefix ; 962*0Sstevel@tonic-gate ($Module_cname = $Module) =~ s/\W/_/g; 963*0Sstevel@tonic-gate ($Packid = $Package) =~ tr/:/_/; 964*0Sstevel@tonic-gate $Packprefix = $Package; 965*0Sstevel@tonic-gate $Packprefix .= "::" if $Packprefix ne ""; 966*0Sstevel@tonic-gate $lastline = ""; 967*0Sstevel@tonic-gate } 968*0Sstevel@tonic-gate 969*0Sstevel@tonic-gate for(;;) { 970*0Sstevel@tonic-gate # Skip embedded PODs 971*0Sstevel@tonic-gate while ($lastline =~ /^=/) { 972*0Sstevel@tonic-gate while ($lastline = <$FH>) { 973*0Sstevel@tonic-gate last if ($lastline =~ /^=cut\s*$/); 974*0Sstevel@tonic-gate } 975*0Sstevel@tonic-gate death ("Error: Unterminated pod") unless $lastline; 976*0Sstevel@tonic-gate $lastline = <$FH>; 977*0Sstevel@tonic-gate chomp $lastline; 978*0Sstevel@tonic-gate $lastline =~ s/^\s+$//; 979*0Sstevel@tonic-gate } 980*0Sstevel@tonic-gate if ($lastline !~ /^\s*#/ || 981*0Sstevel@tonic-gate # CPP directives: 982*0Sstevel@tonic-gate # ANSI: if ifdef ifndef elif else endif define undef 983*0Sstevel@tonic-gate # line error pragma 984*0Sstevel@tonic-gate # gcc: warning include_next 985*0Sstevel@tonic-gate # obj-c: import 986*0Sstevel@tonic-gate # others: ident (gcc notes that some cpps have this one) 987*0Sstevel@tonic-gate $lastline =~ /^#[ \t]*(?:(?:if|ifn?def|elif|else|endif|define|undef|pragma|error|warning|line\s+\d+|ident)\b|(?:include(?:_next)?|import)\s*["<].*[>"])/) { 988*0Sstevel@tonic-gate last if $lastline =~ /^\S/ && @line && $line[-1] eq ""; 989*0Sstevel@tonic-gate push(@line, $lastline); 990*0Sstevel@tonic-gate push(@line_no, $lastline_no) ; 991*0Sstevel@tonic-gate } 992*0Sstevel@tonic-gate 993*0Sstevel@tonic-gate # Read next line and continuation lines 994*0Sstevel@tonic-gate last unless defined($lastline = <$FH>); 995*0Sstevel@tonic-gate $lastline_no = $.; 996*0Sstevel@tonic-gate my $tmp_line; 997*0Sstevel@tonic-gate $lastline .= $tmp_line 998*0Sstevel@tonic-gate while ($lastline =~ /\\$/ && defined($tmp_line = <$FH>)); 999*0Sstevel@tonic-gate 1000*0Sstevel@tonic-gate chomp $lastline; 1001*0Sstevel@tonic-gate $lastline =~ s/^\s+$//; 1002*0Sstevel@tonic-gate } 1003*0Sstevel@tonic-gate pop(@line), pop(@line_no) while @line && $line[-1] eq ""; 1004*0Sstevel@tonic-gate 1; 1005*0Sstevel@tonic-gate} 1006*0Sstevel@tonic-gate 1007*0Sstevel@tonic-gatePARAGRAPH: 1008*0Sstevel@tonic-gatewhile (fetch_para()) { 1009*0Sstevel@tonic-gate # Print initial preprocessor statements and blank lines 1010*0Sstevel@tonic-gate while (@line && $line[0] !~ /^[^\#]/) { 1011*0Sstevel@tonic-gate my $line = shift(@line); 1012*0Sstevel@tonic-gate print $line, "\n"; 1013*0Sstevel@tonic-gate next unless $line =~ /^\#\s*((if)(?:n?def)?|elsif|else|endif)\b/; 1014*0Sstevel@tonic-gate my $statement = $+; 1015*0Sstevel@tonic-gate if ($statement eq 'if') { 1016*0Sstevel@tonic-gate $XSS_work_idx = @XSStack; 1017*0Sstevel@tonic-gate push(@XSStack, {type => 'if'}); 1018*0Sstevel@tonic-gate } else { 1019*0Sstevel@tonic-gate death ("Error: `$statement' with no matching `if'") 1020*0Sstevel@tonic-gate if $XSStack[-1]{type} ne 'if'; 1021*0Sstevel@tonic-gate if ($XSStack[-1]{varname}) { 1022*0Sstevel@tonic-gate push(@InitFileCode, "#endif\n"); 1023*0Sstevel@tonic-gate push(@BootCode, "#endif"); 1024*0Sstevel@tonic-gate } 1025*0Sstevel@tonic-gate 1026*0Sstevel@tonic-gate my(@fns) = keys %{$XSStack[-1]{functions}}; 1027*0Sstevel@tonic-gate if ($statement ne 'endif') { 1028*0Sstevel@tonic-gate # Hide the functions defined in other #if branches, and reset. 1029*0Sstevel@tonic-gate @{$XSStack[-1]{other_functions}}{@fns} = (1) x @fns; 1030*0Sstevel@tonic-gate @{$XSStack[-1]}{qw(varname functions)} = ('', {}); 1031*0Sstevel@tonic-gate } else { 1032*0Sstevel@tonic-gate my($tmp) = pop(@XSStack); 1033*0Sstevel@tonic-gate 0 while (--$XSS_work_idx 1034*0Sstevel@tonic-gate && $XSStack[$XSS_work_idx]{type} ne 'if'); 1035*0Sstevel@tonic-gate # Keep all new defined functions 1036*0Sstevel@tonic-gate push(@fns, keys %{$tmp->{other_functions}}); 1037*0Sstevel@tonic-gate @{$XSStack[$XSS_work_idx]{functions}}{@fns} = (1) x @fns; 1038*0Sstevel@tonic-gate } 1039*0Sstevel@tonic-gate } 1040*0Sstevel@tonic-gate } 1041*0Sstevel@tonic-gate 1042*0Sstevel@tonic-gate next PARAGRAPH unless @line; 1043*0Sstevel@tonic-gate 1044*0Sstevel@tonic-gate if ($XSS_work_idx && !$XSStack[$XSS_work_idx]{varname}) { 1045*0Sstevel@tonic-gate # We are inside an #if, but have not yet #defined its xsubpp variable. 1046*0Sstevel@tonic-gate print "#define $cpp_next_tmp 1\n\n"; 1047*0Sstevel@tonic-gate push(@InitFileCode, "#if $cpp_next_tmp\n"); 1048*0Sstevel@tonic-gate push(@BootCode, "#if $cpp_next_tmp"); 1049*0Sstevel@tonic-gate $XSStack[$XSS_work_idx]{varname} = $cpp_next_tmp++; 1050*0Sstevel@tonic-gate } 1051*0Sstevel@tonic-gate 1052*0Sstevel@tonic-gate death ("Code is not inside a function" 1053*0Sstevel@tonic-gate ." (maybe last function was ended by a blank line " 1054*0Sstevel@tonic-gate ." followed by a statement on column one?)") 1055*0Sstevel@tonic-gate if $line[0] =~ /^\s/; 1056*0Sstevel@tonic-gate 1057*0Sstevel@tonic-gate # initialize info arrays 1058*0Sstevel@tonic-gate undef(%args_match); 1059*0Sstevel@tonic-gate undef(%var_types); 1060*0Sstevel@tonic-gate undef(%defaults); 1061*0Sstevel@tonic-gate undef($class); 1062*0Sstevel@tonic-gate undef($static); 1063*0Sstevel@tonic-gate undef($elipsis); 1064*0Sstevel@tonic-gate undef($wantRETVAL) ; 1065*0Sstevel@tonic-gate undef($RETVAL_no_return) ; 1066*0Sstevel@tonic-gate undef(%arg_list) ; 1067*0Sstevel@tonic-gate undef(@proto_arg) ; 1068*0Sstevel@tonic-gate undef(@fake_INPUT_pre) ; # For length(s) generated variables 1069*0Sstevel@tonic-gate undef(@fake_INPUT) ; 1070*0Sstevel@tonic-gate undef($processing_arg_with_types) ; 1071*0Sstevel@tonic-gate undef(%argtype_seen) ; 1072*0Sstevel@tonic-gate undef(@outlist) ; 1073*0Sstevel@tonic-gate undef(%in_out) ; 1074*0Sstevel@tonic-gate undef(%lengthof) ; 1075*0Sstevel@tonic-gate # undef(%islengthof) ; 1076*0Sstevel@tonic-gate undef($proto_in_this_xsub) ; 1077*0Sstevel@tonic-gate undef($scope_in_this_xsub) ; 1078*0Sstevel@tonic-gate undef($interface); 1079*0Sstevel@tonic-gate undef($prepush_done); 1080*0Sstevel@tonic-gate $interface_macro = 'XSINTERFACE_FUNC' ; 1081*0Sstevel@tonic-gate $interface_macro_set = 'XSINTERFACE_FUNC_SET' ; 1082*0Sstevel@tonic-gate $ProtoThisXSUB = $WantPrototypes ; 1083*0Sstevel@tonic-gate $ScopeThisXSUB = 0; 1084*0Sstevel@tonic-gate $xsreturn = 0; 1085*0Sstevel@tonic-gate 1086*0Sstevel@tonic-gate $_ = shift(@line); 1087*0Sstevel@tonic-gate while ($kwd = check_keyword("REQUIRE|PROTOTYPES|FALLBACK|VERSIONCHECK|INCLUDE")) { 1088*0Sstevel@tonic-gate &{"${kwd}_handler"}() ; 1089*0Sstevel@tonic-gate next PARAGRAPH unless @line ; 1090*0Sstevel@tonic-gate $_ = shift(@line); 1091*0Sstevel@tonic-gate } 1092*0Sstevel@tonic-gate 1093*0Sstevel@tonic-gate if (check_keyword("BOOT")) { 1094*0Sstevel@tonic-gate &check_cpp; 1095*0Sstevel@tonic-gate push (@BootCode, "#line $line_no[@line_no - @line] \"$filename\"") 1096*0Sstevel@tonic-gate if $WantLineNumbers && $line[0] !~ /^\s*#\s*line\b/; 1097*0Sstevel@tonic-gate push (@BootCode, @line, "") ; 1098*0Sstevel@tonic-gate next PARAGRAPH ; 1099*0Sstevel@tonic-gate } 1100*0Sstevel@tonic-gate 1101*0Sstevel@tonic-gate 1102*0Sstevel@tonic-gate # extract return type, function name and arguments 1103*0Sstevel@tonic-gate ($ret_type) = TidyType($_); 1104*0Sstevel@tonic-gate $RETVAL_no_return = 1 if $ret_type =~ s/^NO_OUTPUT\s+//; 1105*0Sstevel@tonic-gate 1106*0Sstevel@tonic-gate # Allow one-line ANSI-like declaration 1107*0Sstevel@tonic-gate unshift @line, $2 1108*0Sstevel@tonic-gate if $process_argtypes 1109*0Sstevel@tonic-gate and $ret_type =~ s/^(.*?\w.*?)\s*\b(\w+\s*\(.*)/$1/s; 1110*0Sstevel@tonic-gate 1111*0Sstevel@tonic-gate # a function definition needs at least 2 lines 1112*0Sstevel@tonic-gate blurt ("Error: Function definition too short '$ret_type'"), next PARAGRAPH 1113*0Sstevel@tonic-gate unless @line ; 1114*0Sstevel@tonic-gate 1115*0Sstevel@tonic-gate $static = 1 if $ret_type =~ s/^static\s+//; 1116*0Sstevel@tonic-gate 1117*0Sstevel@tonic-gate $func_header = shift(@line); 1118*0Sstevel@tonic-gate blurt ("Error: Cannot parse function definition from '$func_header'"), next PARAGRAPH 1119*0Sstevel@tonic-gate unless $func_header =~ /^(?:([\w:]*)::)?(\w+)\s*\(\s*(.*?)\s*\)\s*(const)?\s*(;\s*)?$/s; 1120*0Sstevel@tonic-gate 1121*0Sstevel@tonic-gate ($class, $func_name, $orig_args) = ($1, $2, $3) ; 1122*0Sstevel@tonic-gate $class = "$4 $class" if $4; 1123*0Sstevel@tonic-gate ($pname = $func_name) =~ s/^($Prefix)?/$Packprefix/; 1124*0Sstevel@tonic-gate ($clean_func_name = $func_name) =~ s/^$Prefix//; 1125*0Sstevel@tonic-gate $Full_func_name = "${Packid}_$clean_func_name"; 1126*0Sstevel@tonic-gate if ($Is_VMS) { $Full_func_name = $SymSet->addsym($Full_func_name); } 1127*0Sstevel@tonic-gate 1128*0Sstevel@tonic-gate # Check for duplicate function definition 1129*0Sstevel@tonic-gate for $tmp (@XSStack) { 1130*0Sstevel@tonic-gate next unless defined $tmp->{functions}{$Full_func_name}; 1131*0Sstevel@tonic-gate Warn("Warning: duplicate function definition '$clean_func_name' detected"); 1132*0Sstevel@tonic-gate last; 1133*0Sstevel@tonic-gate } 1134*0Sstevel@tonic-gate $XSStack[$XSS_work_idx]{functions}{$Full_func_name} ++ ; 1135*0Sstevel@tonic-gate %XsubAliases = %XsubAliasValues = %Interfaces = @Attributes = (); 1136*0Sstevel@tonic-gate $DoSetMagic = 1; 1137*0Sstevel@tonic-gate 1138*0Sstevel@tonic-gate $orig_args =~ s/\\\s*/ /g; # process line continuations 1139*0Sstevel@tonic-gate 1140*0Sstevel@tonic-gate my %only_C_inlist; # Not in the signature of Perl function 1141*0Sstevel@tonic-gate if ($process_argtypes and $orig_args =~ /\S/) { 1142*0Sstevel@tonic-gate my $args = "$orig_args ,"; 1143*0Sstevel@tonic-gate if ($args =~ /^( (??{ $C_arg }) , )* $ /x) { 1144*0Sstevel@tonic-gate @args = ($args =~ /\G ( (??{ $C_arg }) ) , /xg); 1145*0Sstevel@tonic-gate for ( @args ) { 1146*0Sstevel@tonic-gate s/^\s+//; 1147*0Sstevel@tonic-gate s/\s+$//; 1148*0Sstevel@tonic-gate my ($arg, $default) = / ( [^=]* ) ( (?: = .* )? ) /x; 1149*0Sstevel@tonic-gate my ($pre, $name) = ($arg =~ /(.*?) \s* 1150*0Sstevel@tonic-gate \b ( \w+ | length\( \s*\w+\s* \) ) 1151*0Sstevel@tonic-gate \s* $ /x); 1152*0Sstevel@tonic-gate next unless length $pre; 1153*0Sstevel@tonic-gate my $out_type; 1154*0Sstevel@tonic-gate my $inout_var; 1155*0Sstevel@tonic-gate if ($process_inout and s/^(IN|IN_OUTLIST|OUTLIST|OUT|IN_OUT)\s+//) { 1156*0Sstevel@tonic-gate my $type = $1; 1157*0Sstevel@tonic-gate $out_type = $type if $type ne 'IN'; 1158*0Sstevel@tonic-gate $arg =~ s/^(IN|IN_OUTLIST|OUTLIST|OUT|IN_OUT)\s+//; 1159*0Sstevel@tonic-gate $pre =~ s/^(IN|IN_OUTLIST|OUTLIST|OUT|IN_OUT)\s+//; 1160*0Sstevel@tonic-gate } 1161*0Sstevel@tonic-gate my $islength; 1162*0Sstevel@tonic-gate if ($name =~ /^length\( \s* (\w+) \s* \)\z/x) { 1163*0Sstevel@tonic-gate $name = "XSauto_length_of_$1"; 1164*0Sstevel@tonic-gate $islength = 1; 1165*0Sstevel@tonic-gate die "Default value on length() argument: `$_'" 1166*0Sstevel@tonic-gate if length $default; 1167*0Sstevel@tonic-gate } 1168*0Sstevel@tonic-gate if (length $pre or $islength) { # Has a type 1169*0Sstevel@tonic-gate if ($islength) { 1170*0Sstevel@tonic-gate push @fake_INPUT_pre, $arg; 1171*0Sstevel@tonic-gate } else { 1172*0Sstevel@tonic-gate push @fake_INPUT, $arg; 1173*0Sstevel@tonic-gate } 1174*0Sstevel@tonic-gate # warn "pushing '$arg'\n"; 1175*0Sstevel@tonic-gate $argtype_seen{$name}++; 1176*0Sstevel@tonic-gate $_ = "$name$default"; # Assigns to @args 1177*0Sstevel@tonic-gate } 1178*0Sstevel@tonic-gate $only_C_inlist{$_} = 1 if $out_type eq "OUTLIST" or $islength; 1179*0Sstevel@tonic-gate push @outlist, $name if $out_type =~ /OUTLIST$/; 1180*0Sstevel@tonic-gate $in_out{$name} = $out_type if $out_type; 1181*0Sstevel@tonic-gate } 1182*0Sstevel@tonic-gate } else { 1183*0Sstevel@tonic-gate @args = split(/\s*,\s*/, $orig_args); 1184*0Sstevel@tonic-gate Warn("Warning: cannot parse argument list '$orig_args', fallback to split"); 1185*0Sstevel@tonic-gate } 1186*0Sstevel@tonic-gate } else { 1187*0Sstevel@tonic-gate @args = split(/\s*,\s*/, $orig_args); 1188*0Sstevel@tonic-gate for (@args) { 1189*0Sstevel@tonic-gate if ($process_inout and s/^(IN|IN_OUTLIST|OUTLIST|IN_OUT|OUT)\s+//) { 1190*0Sstevel@tonic-gate my $out_type = $1; 1191*0Sstevel@tonic-gate next if $out_type eq 'IN'; 1192*0Sstevel@tonic-gate $only_C_inlist{$_} = 1 if $out_type eq "OUTLIST"; 1193*0Sstevel@tonic-gate push @outlist, $name if $out_type =~ /OUTLIST$/; 1194*0Sstevel@tonic-gate $in_out{$_} = $out_type; 1195*0Sstevel@tonic-gate } 1196*0Sstevel@tonic-gate } 1197*0Sstevel@tonic-gate } 1198*0Sstevel@tonic-gate if (defined($class)) { 1199*0Sstevel@tonic-gate my $arg0 = ((defined($static) or $func_name eq 'new') 1200*0Sstevel@tonic-gate ? "CLASS" : "THIS"); 1201*0Sstevel@tonic-gate unshift(@args, $arg0); 1202*0Sstevel@tonic-gate ($report_args = "$arg0, $report_args") =~ s/^\w+, $/$arg0/; 1203*0Sstevel@tonic-gate } 1204*0Sstevel@tonic-gate my $extra_args = 0; 1205*0Sstevel@tonic-gate @args_num = (); 1206*0Sstevel@tonic-gate $num_args = 0; 1207*0Sstevel@tonic-gate my $report_args = ''; 1208*0Sstevel@tonic-gate foreach $i (0 .. $#args) { 1209*0Sstevel@tonic-gate if ($args[$i] =~ s/\.\.\.//) { 1210*0Sstevel@tonic-gate $elipsis = 1; 1211*0Sstevel@tonic-gate if ($args[$i] eq '' && $i == $#args) { 1212*0Sstevel@tonic-gate $report_args .= ", ..."; 1213*0Sstevel@tonic-gate pop(@args); 1214*0Sstevel@tonic-gate last; 1215*0Sstevel@tonic-gate } 1216*0Sstevel@tonic-gate } 1217*0Sstevel@tonic-gate if ($only_C_inlist{$args[$i]}) { 1218*0Sstevel@tonic-gate push @args_num, undef; 1219*0Sstevel@tonic-gate } else { 1220*0Sstevel@tonic-gate push @args_num, ++$num_args; 1221*0Sstevel@tonic-gate $report_args .= ", $args[$i]"; 1222*0Sstevel@tonic-gate } 1223*0Sstevel@tonic-gate if ($args[$i] =~ /^([^=]*[^\s=])\s*=\s*(.*)/s) { 1224*0Sstevel@tonic-gate $extra_args++; 1225*0Sstevel@tonic-gate $args[$i] = $1; 1226*0Sstevel@tonic-gate $defaults{$args[$i]} = $2; 1227*0Sstevel@tonic-gate $defaults{$args[$i]} =~ s/"/\\"/g; 1228*0Sstevel@tonic-gate } 1229*0Sstevel@tonic-gate $proto_arg[$i+1] = "\$" ; 1230*0Sstevel@tonic-gate } 1231*0Sstevel@tonic-gate $min_args = $num_args - $extra_args; 1232*0Sstevel@tonic-gate $report_args =~ s/"/\\"/g; 1233*0Sstevel@tonic-gate $report_args =~ s/^,\s+//; 1234*0Sstevel@tonic-gate my @func_args = @args; 1235*0Sstevel@tonic-gate shift @func_args if defined($class); 1236*0Sstevel@tonic-gate 1237*0Sstevel@tonic-gate for (@func_args) { 1238*0Sstevel@tonic-gate s/^/&/ if $in_out{$_}; 1239*0Sstevel@tonic-gate } 1240*0Sstevel@tonic-gate $func_args = join(", ", @func_args); 1241*0Sstevel@tonic-gate @args_match{@args} = @args_num; 1242*0Sstevel@tonic-gate 1243*0Sstevel@tonic-gate $PPCODE = grep(/^\s*PPCODE\s*:/, @line); 1244*0Sstevel@tonic-gate $CODE = grep(/^\s*CODE\s*:/, @line); 1245*0Sstevel@tonic-gate # Detect CODE: blocks which use ST(n)= or XST_m*(n,v) 1246*0Sstevel@tonic-gate # to set explicit return values. 1247*0Sstevel@tonic-gate $EXPLICIT_RETURN = ($CODE && 1248*0Sstevel@tonic-gate ("@line" =~ /(\bST\s*\([^;]*=) | (\bXST_m\w+\s*\()/x )); 1249*0Sstevel@tonic-gate $ALIAS = grep(/^\s*ALIAS\s*:/, @line); 1250*0Sstevel@tonic-gate $INTERFACE = grep(/^\s*INTERFACE\s*:/, @line); 1251*0Sstevel@tonic-gate 1252*0Sstevel@tonic-gate $xsreturn = 1 if $EXPLICIT_RETURN; 1253*0Sstevel@tonic-gate 1254*0Sstevel@tonic-gate # print function header 1255*0Sstevel@tonic-gate print Q<<"EOF"; 1256*0Sstevel@tonic-gate#XS(XS_${Full_func_name}); /* prototype to pass -Wmissing-prototypes */ 1257*0Sstevel@tonic-gate#XS(XS_${Full_func_name}) 1258*0Sstevel@tonic-gate#[[ 1259*0Sstevel@tonic-gate# dXSARGS; 1260*0Sstevel@tonic-gateEOF 1261*0Sstevel@tonic-gate print Q<<"EOF" if $ALIAS ; 1262*0Sstevel@tonic-gate# dXSI32; 1263*0Sstevel@tonic-gateEOF 1264*0Sstevel@tonic-gate print Q<<"EOF" if $INTERFACE ; 1265*0Sstevel@tonic-gate# dXSFUNCTION($ret_type); 1266*0Sstevel@tonic-gateEOF 1267*0Sstevel@tonic-gate if ($elipsis) { 1268*0Sstevel@tonic-gate $cond = ($min_args ? qq(items < $min_args) : 0); 1269*0Sstevel@tonic-gate } 1270*0Sstevel@tonic-gate elsif ($min_args == $num_args) { 1271*0Sstevel@tonic-gate $cond = qq(items != $min_args); 1272*0Sstevel@tonic-gate } 1273*0Sstevel@tonic-gate else { 1274*0Sstevel@tonic-gate $cond = qq(items < $min_args || items > $num_args); 1275*0Sstevel@tonic-gate } 1276*0Sstevel@tonic-gate 1277*0Sstevel@tonic-gate print Q<<"EOF" if $except; 1278*0Sstevel@tonic-gate# char errbuf[1024]; 1279*0Sstevel@tonic-gate# *errbuf = '\0'; 1280*0Sstevel@tonic-gateEOF 1281*0Sstevel@tonic-gate 1282*0Sstevel@tonic-gate if ($ALIAS) 1283*0Sstevel@tonic-gate { print Q<<"EOF" if $cond } 1284*0Sstevel@tonic-gate# if ($cond) 1285*0Sstevel@tonic-gate# Perl_croak(aTHX_ "Usage: %s($report_args)", GvNAME(CvGV(cv))); 1286*0Sstevel@tonic-gateEOF 1287*0Sstevel@tonic-gate else 1288*0Sstevel@tonic-gate { print Q<<"EOF" if $cond } 1289*0Sstevel@tonic-gate# if ($cond) 1290*0Sstevel@tonic-gate# Perl_croak(aTHX_ "Usage: $pname($report_args)"); 1291*0Sstevel@tonic-gateEOF 1292*0Sstevel@tonic-gate 1293*0Sstevel@tonic-gate #gcc -Wall: if an xsub has no arguments and PPCODE is used 1294*0Sstevel@tonic-gate #it is likely none of ST, XSRETURN or XSprePUSH macros are used 1295*0Sstevel@tonic-gate #hence `ax' (setup by dXSARGS) is unused 1296*0Sstevel@tonic-gate #XXX: could breakup the dXSARGS; into dSP;dMARK;dITEMS 1297*0Sstevel@tonic-gate #but such a move could break third-party extensions 1298*0Sstevel@tonic-gate print Q<<"EOF" if $PPCODE and $num_args == 0; 1299*0Sstevel@tonic-gate# PERL_UNUSED_VAR(ax); /* -Wall */ 1300*0Sstevel@tonic-gateEOF 1301*0Sstevel@tonic-gate 1302*0Sstevel@tonic-gate print Q<<"EOF" if $PPCODE; 1303*0Sstevel@tonic-gate# SP -= items; 1304*0Sstevel@tonic-gateEOF 1305*0Sstevel@tonic-gate 1306*0Sstevel@tonic-gate # Now do a block of some sort. 1307*0Sstevel@tonic-gate 1308*0Sstevel@tonic-gate $condnum = 0; 1309*0Sstevel@tonic-gate $cond = ''; # last CASE: condidional 1310*0Sstevel@tonic-gate push(@line, "$END:"); 1311*0Sstevel@tonic-gate push(@line_no, $line_no[-1]); 1312*0Sstevel@tonic-gate $_ = ''; 1313*0Sstevel@tonic-gate &check_cpp; 1314*0Sstevel@tonic-gate while (@line) { 1315*0Sstevel@tonic-gate &CASE_handler if check_keyword("CASE"); 1316*0Sstevel@tonic-gate print Q<<"EOF"; 1317*0Sstevel@tonic-gate# $except [[ 1318*0Sstevel@tonic-gateEOF 1319*0Sstevel@tonic-gate 1320*0Sstevel@tonic-gate # do initialization of input variables 1321*0Sstevel@tonic-gate $thisdone = 0; 1322*0Sstevel@tonic-gate $retvaldone = 0; 1323*0Sstevel@tonic-gate $deferred = ""; 1324*0Sstevel@tonic-gate %arg_list = () ; 1325*0Sstevel@tonic-gate $gotRETVAL = 0; 1326*0Sstevel@tonic-gate 1327*0Sstevel@tonic-gate INPUT_handler() ; 1328*0Sstevel@tonic-gate process_keyword("INPUT|PREINIT|INTERFACE_MACRO|C_ARGS|ALIAS|ATTRS|PROTOTYPE|SCOPE|OVERLOAD") ; 1329*0Sstevel@tonic-gate 1330*0Sstevel@tonic-gate print Q<<"EOF" if $ScopeThisXSUB; 1331*0Sstevel@tonic-gate# ENTER; 1332*0Sstevel@tonic-gate# [[ 1333*0Sstevel@tonic-gateEOF 1334*0Sstevel@tonic-gate 1335*0Sstevel@tonic-gate if (!$thisdone && defined($class)) { 1336*0Sstevel@tonic-gate if (defined($static) or $func_name eq 'new') { 1337*0Sstevel@tonic-gate print "\tchar *"; 1338*0Sstevel@tonic-gate $var_types{"CLASS"} = "char *"; 1339*0Sstevel@tonic-gate &generate_init("char *", 1, "CLASS"); 1340*0Sstevel@tonic-gate } 1341*0Sstevel@tonic-gate else { 1342*0Sstevel@tonic-gate print "\t$class *"; 1343*0Sstevel@tonic-gate $var_types{"THIS"} = "$class *"; 1344*0Sstevel@tonic-gate &generate_init("$class *", 1, "THIS"); 1345*0Sstevel@tonic-gate } 1346*0Sstevel@tonic-gate } 1347*0Sstevel@tonic-gate 1348*0Sstevel@tonic-gate # do code 1349*0Sstevel@tonic-gate if (/^\s*NOT_IMPLEMENTED_YET/) { 1350*0Sstevel@tonic-gate print "\n\tPerl_croak(aTHX_ \"$pname: not implemented yet\");\n"; 1351*0Sstevel@tonic-gate $_ = '' ; 1352*0Sstevel@tonic-gate } else { 1353*0Sstevel@tonic-gate if ($ret_type ne "void") { 1354*0Sstevel@tonic-gate print "\t" . &map_type($ret_type, 'RETVAL') . ";\n" 1355*0Sstevel@tonic-gate if !$retvaldone; 1356*0Sstevel@tonic-gate $args_match{"RETVAL"} = 0; 1357*0Sstevel@tonic-gate $var_types{"RETVAL"} = $ret_type; 1358*0Sstevel@tonic-gate print "\tdXSTARG;\n" 1359*0Sstevel@tonic-gate if $WantOptimize and $targetable{$type_kind{$ret_type}}; 1360*0Sstevel@tonic-gate } 1361*0Sstevel@tonic-gate 1362*0Sstevel@tonic-gate if (@fake_INPUT or @fake_INPUT_pre) { 1363*0Sstevel@tonic-gate unshift @line, @fake_INPUT_pre, @fake_INPUT, $_; 1364*0Sstevel@tonic-gate $_ = ""; 1365*0Sstevel@tonic-gate $processing_arg_with_types = 1; 1366*0Sstevel@tonic-gate INPUT_handler() ; 1367*0Sstevel@tonic-gate } 1368*0Sstevel@tonic-gate print $deferred; 1369*0Sstevel@tonic-gate 1370*0Sstevel@tonic-gate process_keyword("INIT|ALIAS|ATTRS|PROTOTYPE|INTERFACE_MACRO|INTERFACE|C_ARGS|OVERLOAD") ; 1371*0Sstevel@tonic-gate 1372*0Sstevel@tonic-gate if (check_keyword("PPCODE")) { 1373*0Sstevel@tonic-gate print_section(); 1374*0Sstevel@tonic-gate death ("PPCODE must be last thing") if @line; 1375*0Sstevel@tonic-gate print "\tLEAVE;\n" if $ScopeThisXSUB; 1376*0Sstevel@tonic-gate print "\tPUTBACK;\n\treturn;\n"; 1377*0Sstevel@tonic-gate } elsif (check_keyword("CODE")) { 1378*0Sstevel@tonic-gate print_section() ; 1379*0Sstevel@tonic-gate } elsif (defined($class) and $func_name eq "DESTROY") { 1380*0Sstevel@tonic-gate print "\n\t"; 1381*0Sstevel@tonic-gate print "delete THIS;\n"; 1382*0Sstevel@tonic-gate } else { 1383*0Sstevel@tonic-gate print "\n\t"; 1384*0Sstevel@tonic-gate if ($ret_type ne "void") { 1385*0Sstevel@tonic-gate print "RETVAL = "; 1386*0Sstevel@tonic-gate $wantRETVAL = 1; 1387*0Sstevel@tonic-gate } 1388*0Sstevel@tonic-gate if (defined($static)) { 1389*0Sstevel@tonic-gate if ($func_name eq 'new') { 1390*0Sstevel@tonic-gate $func_name = "$class"; 1391*0Sstevel@tonic-gate } else { 1392*0Sstevel@tonic-gate print "${class}::"; 1393*0Sstevel@tonic-gate } 1394*0Sstevel@tonic-gate } elsif (defined($class)) { 1395*0Sstevel@tonic-gate if ($func_name eq 'new') { 1396*0Sstevel@tonic-gate $func_name .= " $class"; 1397*0Sstevel@tonic-gate } else { 1398*0Sstevel@tonic-gate print "THIS->"; 1399*0Sstevel@tonic-gate } 1400*0Sstevel@tonic-gate } 1401*0Sstevel@tonic-gate $func_name =~ s/^($spat)// 1402*0Sstevel@tonic-gate if defined($spat); 1403*0Sstevel@tonic-gate $func_name = 'XSFUNCTION' if $interface; 1404*0Sstevel@tonic-gate print "$func_name($func_args);\n"; 1405*0Sstevel@tonic-gate } 1406*0Sstevel@tonic-gate } 1407*0Sstevel@tonic-gate 1408*0Sstevel@tonic-gate # do output variables 1409*0Sstevel@tonic-gate $gotRETVAL = 0; # 1 if RETVAL seen in OUTPUT section; 1410*0Sstevel@tonic-gate undef $RETVAL_code ; # code to set RETVAL (from OUTPUT section); 1411*0Sstevel@tonic-gate # $wantRETVAL set if 'RETVAL =' autogenerated 1412*0Sstevel@tonic-gate ($wantRETVAL, $ret_type) = (0, 'void') if $RETVAL_no_return; 1413*0Sstevel@tonic-gate undef %outargs ; 1414*0Sstevel@tonic-gate process_keyword("POSTCALL|OUTPUT|ALIAS|ATTRS|PROTOTYPE|OVERLOAD"); 1415*0Sstevel@tonic-gate 1416*0Sstevel@tonic-gate &generate_output($var_types{$_}, $args_match{$_}, $_, $DoSetMagic) 1417*0Sstevel@tonic-gate for grep $in_out{$_} =~ /OUT$/, keys %in_out; 1418*0Sstevel@tonic-gate 1419*0Sstevel@tonic-gate # all OUTPUT done, so now push the return value on the stack 1420*0Sstevel@tonic-gate if ($gotRETVAL && $RETVAL_code) { 1421*0Sstevel@tonic-gate print "\t$RETVAL_code\n"; 1422*0Sstevel@tonic-gate } elsif ($gotRETVAL || $wantRETVAL) { 1423*0Sstevel@tonic-gate my $t = $WantOptimize && $targetable{$type_kind{$ret_type}}; 1424*0Sstevel@tonic-gate my $var = 'RETVAL'; 1425*0Sstevel@tonic-gate my $type = $ret_type; 1426*0Sstevel@tonic-gate 1427*0Sstevel@tonic-gate # 0: type, 1: with_size, 2: how, 3: how_size 1428*0Sstevel@tonic-gate if ($t and not $t->[1] and $t->[0] eq 'p') { 1429*0Sstevel@tonic-gate # PUSHp corresponds to setpvn. Treate setpv directly 1430*0Sstevel@tonic-gate my $what = eval qq("$t->[2]"); 1431*0Sstevel@tonic-gate warn $@ if $@; 1432*0Sstevel@tonic-gate 1433*0Sstevel@tonic-gate print "\tsv_setpv(TARG, $what); XSprePUSH; PUSHTARG;\n"; 1434*0Sstevel@tonic-gate $prepush_done = 1; 1435*0Sstevel@tonic-gate } 1436*0Sstevel@tonic-gate elsif ($t) { 1437*0Sstevel@tonic-gate my $what = eval qq("$t->[2]"); 1438*0Sstevel@tonic-gate warn $@ if $@; 1439*0Sstevel@tonic-gate 1440*0Sstevel@tonic-gate my $size = $t->[3]; 1441*0Sstevel@tonic-gate $size = '' unless defined $size; 1442*0Sstevel@tonic-gate $size = eval qq("$size"); 1443*0Sstevel@tonic-gate warn $@ if $@; 1444*0Sstevel@tonic-gate print "\tXSprePUSH; PUSH$t->[0]($what$size);\n"; 1445*0Sstevel@tonic-gate $prepush_done = 1; 1446*0Sstevel@tonic-gate } 1447*0Sstevel@tonic-gate else { 1448*0Sstevel@tonic-gate # RETVAL almost never needs SvSETMAGIC() 1449*0Sstevel@tonic-gate &generate_output($ret_type, 0, 'RETVAL', 0); 1450*0Sstevel@tonic-gate } 1451*0Sstevel@tonic-gate } 1452*0Sstevel@tonic-gate 1453*0Sstevel@tonic-gate $xsreturn = 1 if $ret_type ne "void"; 1454*0Sstevel@tonic-gate my $num = $xsreturn; 1455*0Sstevel@tonic-gate my $c = @outlist; 1456*0Sstevel@tonic-gate # (PP)CODE set different values of SP; reset to PPCODE's with 0 output 1457*0Sstevel@tonic-gate print "\tXSprePUSH;" if $c and not $prepush_done; 1458*0Sstevel@tonic-gate # Take into account stuff already put on stack 1459*0Sstevel@tonic-gate print "\t++SP;" if $c and not $prepush_done and $xsreturn; 1460*0Sstevel@tonic-gate # Now SP corresponds to ST($xsreturn), so one can combine PUSH and ST() 1461*0Sstevel@tonic-gate print "\tEXTEND(SP,$c);\n" if $c; 1462*0Sstevel@tonic-gate $xsreturn += $c; 1463*0Sstevel@tonic-gate generate_output($var_types{$_}, $num++, $_, 0, 1) for @outlist; 1464*0Sstevel@tonic-gate 1465*0Sstevel@tonic-gate # do cleanup 1466*0Sstevel@tonic-gate process_keyword("CLEANUP|ALIAS|ATTRS|PROTOTYPE|OVERLOAD") ; 1467*0Sstevel@tonic-gate 1468*0Sstevel@tonic-gate print Q<<"EOF" if $ScopeThisXSUB; 1469*0Sstevel@tonic-gate# ]] 1470*0Sstevel@tonic-gateEOF 1471*0Sstevel@tonic-gate print Q<<"EOF" if $ScopeThisXSUB and not $PPCODE; 1472*0Sstevel@tonic-gate# LEAVE; 1473*0Sstevel@tonic-gateEOF 1474*0Sstevel@tonic-gate 1475*0Sstevel@tonic-gate # print function trailer 1476*0Sstevel@tonic-gate print Q<<EOF; 1477*0Sstevel@tonic-gate# ]] 1478*0Sstevel@tonic-gateEOF 1479*0Sstevel@tonic-gate print Q<<EOF if $except; 1480*0Sstevel@tonic-gate# BEGHANDLERS 1481*0Sstevel@tonic-gate# CATCHALL 1482*0Sstevel@tonic-gate# sprintf(errbuf, "%s: %s\\tpropagated", Xname, Xreason); 1483*0Sstevel@tonic-gate# ENDHANDLERS 1484*0Sstevel@tonic-gateEOF 1485*0Sstevel@tonic-gate if (check_keyword("CASE")) { 1486*0Sstevel@tonic-gate blurt ("Error: No `CASE:' at top of function") 1487*0Sstevel@tonic-gate unless $condnum; 1488*0Sstevel@tonic-gate $_ = "CASE: $_"; # Restore CASE: label 1489*0Sstevel@tonic-gate next; 1490*0Sstevel@tonic-gate } 1491*0Sstevel@tonic-gate last if $_ eq "$END:"; 1492*0Sstevel@tonic-gate death(/^$BLOCK_re/o ? "Misplaced `$1:'" : "Junk at end of function"); 1493*0Sstevel@tonic-gate } 1494*0Sstevel@tonic-gate 1495*0Sstevel@tonic-gate print Q<<EOF if $except; 1496*0Sstevel@tonic-gate# if (errbuf[0]) 1497*0Sstevel@tonic-gate# Perl_croak(aTHX_ errbuf); 1498*0Sstevel@tonic-gateEOF 1499*0Sstevel@tonic-gate 1500*0Sstevel@tonic-gate if ($xsreturn) { 1501*0Sstevel@tonic-gate print Q<<EOF unless $PPCODE; 1502*0Sstevel@tonic-gate# XSRETURN($xsreturn); 1503*0Sstevel@tonic-gateEOF 1504*0Sstevel@tonic-gate } else { 1505*0Sstevel@tonic-gate print Q<<EOF unless $PPCODE; 1506*0Sstevel@tonic-gate# XSRETURN_EMPTY; 1507*0Sstevel@tonic-gateEOF 1508*0Sstevel@tonic-gate } 1509*0Sstevel@tonic-gate 1510*0Sstevel@tonic-gate print Q<<EOF; 1511*0Sstevel@tonic-gate#]] 1512*0Sstevel@tonic-gate# 1513*0Sstevel@tonic-gateEOF 1514*0Sstevel@tonic-gate 1515*0Sstevel@tonic-gate my $newXS = "newXS" ; 1516*0Sstevel@tonic-gate my $proto = "" ; 1517*0Sstevel@tonic-gate 1518*0Sstevel@tonic-gate # Build the prototype string for the xsub 1519*0Sstevel@tonic-gate if ($ProtoThisXSUB) { 1520*0Sstevel@tonic-gate $newXS = "newXSproto"; 1521*0Sstevel@tonic-gate 1522*0Sstevel@tonic-gate if ($ProtoThisXSUB eq 2) { 1523*0Sstevel@tonic-gate # User has specified empty prototype 1524*0Sstevel@tonic-gate $proto = ', ""' ; 1525*0Sstevel@tonic-gate } 1526*0Sstevel@tonic-gate elsif ($ProtoThisXSUB ne 1) { 1527*0Sstevel@tonic-gate # User has specified a prototype 1528*0Sstevel@tonic-gate $proto = ', "' . $ProtoThisXSUB . '"'; 1529*0Sstevel@tonic-gate } 1530*0Sstevel@tonic-gate else { 1531*0Sstevel@tonic-gate my $s = ';'; 1532*0Sstevel@tonic-gate if ($min_args < $num_args) { 1533*0Sstevel@tonic-gate $s = ''; 1534*0Sstevel@tonic-gate $proto_arg[$min_args] .= ";" ; 1535*0Sstevel@tonic-gate } 1536*0Sstevel@tonic-gate push @proto_arg, "$s\@" 1537*0Sstevel@tonic-gate if $elipsis ; 1538*0Sstevel@tonic-gate 1539*0Sstevel@tonic-gate $proto = ', "' . join ("", @proto_arg) . '"'; 1540*0Sstevel@tonic-gate } 1541*0Sstevel@tonic-gate } 1542*0Sstevel@tonic-gate 1543*0Sstevel@tonic-gate if (%XsubAliases) { 1544*0Sstevel@tonic-gate $XsubAliases{$pname} = 0 1545*0Sstevel@tonic-gate unless defined $XsubAliases{$pname} ; 1546*0Sstevel@tonic-gate while ( ($name, $value) = each %XsubAliases) { 1547*0Sstevel@tonic-gate push(@InitFileCode, Q<<"EOF"); 1548*0Sstevel@tonic-gate# cv = newXS(\"$name\", XS_$Full_func_name, file); 1549*0Sstevel@tonic-gate# XSANY.any_i32 = $value ; 1550*0Sstevel@tonic-gateEOF 1551*0Sstevel@tonic-gate push(@InitFileCode, Q<<"EOF") if $proto; 1552*0Sstevel@tonic-gate# sv_setpv((SV*)cv$proto) ; 1553*0Sstevel@tonic-gateEOF 1554*0Sstevel@tonic-gate } 1555*0Sstevel@tonic-gate } 1556*0Sstevel@tonic-gate elsif (@Attributes) { 1557*0Sstevel@tonic-gate push(@InitFileCode, Q<<"EOF"); 1558*0Sstevel@tonic-gate# cv = newXS(\"$pname\", XS_$Full_func_name, file); 1559*0Sstevel@tonic-gate# apply_attrs_string("$Package", cv, "@Attributes", 0); 1560*0Sstevel@tonic-gateEOF 1561*0Sstevel@tonic-gate } 1562*0Sstevel@tonic-gate elsif ($interface) { 1563*0Sstevel@tonic-gate while ( ($name, $value) = each %Interfaces) { 1564*0Sstevel@tonic-gate $name = "$Package\::$name" unless $name =~ /::/; 1565*0Sstevel@tonic-gate push(@InitFileCode, Q<<"EOF"); 1566*0Sstevel@tonic-gate# cv = newXS(\"$name\", XS_$Full_func_name, file); 1567*0Sstevel@tonic-gate# $interface_macro_set(cv,$value) ; 1568*0Sstevel@tonic-gateEOF 1569*0Sstevel@tonic-gate push(@InitFileCode, Q<<"EOF") if $proto; 1570*0Sstevel@tonic-gate# sv_setpv((SV*)cv$proto) ; 1571*0Sstevel@tonic-gateEOF 1572*0Sstevel@tonic-gate } 1573*0Sstevel@tonic-gate } 1574*0Sstevel@tonic-gate else { 1575*0Sstevel@tonic-gate push(@InitFileCode, 1576*0Sstevel@tonic-gate " ${newXS}(\"$pname\", XS_$Full_func_name, file$proto);\n"); 1577*0Sstevel@tonic-gate } 1578*0Sstevel@tonic-gate} 1579*0Sstevel@tonic-gate 1580*0Sstevel@tonic-gateif ($Overload) # make it findable with fetchmethod 1581*0Sstevel@tonic-gate{ 1582*0Sstevel@tonic-gate 1583*0Sstevel@tonic-gate print Q<<"EOF"; 1584*0Sstevel@tonic-gate#XS(XS_${Packid}_nil); /* prototype to pass -Wmissing-prototypes */ 1585*0Sstevel@tonic-gate#XS(XS_${Packid}_nil) 1586*0Sstevel@tonic-gate#{ 1587*0Sstevel@tonic-gate# XSRETURN_EMPTY; 1588*0Sstevel@tonic-gate#} 1589*0Sstevel@tonic-gate# 1590*0Sstevel@tonic-gateEOF 1591*0Sstevel@tonic-gate unshift(@InitFileCode, <<"MAKE_FETCHMETHOD_WORK"); 1592*0Sstevel@tonic-gate /* Making a sub named "${Package}::()" allows the package */ 1593*0Sstevel@tonic-gate /* to be findable via fetchmethod(), and causes */ 1594*0Sstevel@tonic-gate /* overload::Overloaded("${Package}") to return true. */ 1595*0Sstevel@tonic-gate newXS("${Package}::()", XS_${Packid}_nil, file$proto); 1596*0Sstevel@tonic-gateMAKE_FETCHMETHOD_WORK 1597*0Sstevel@tonic-gate} 1598*0Sstevel@tonic-gate 1599*0Sstevel@tonic-gate# print initialization routine 1600*0Sstevel@tonic-gate 1601*0Sstevel@tonic-gateprint Q<<"EOF"; 1602*0Sstevel@tonic-gate##ifdef __cplusplus 1603*0Sstevel@tonic-gate#extern "C" 1604*0Sstevel@tonic-gate##endif 1605*0Sstevel@tonic-gateEOF 1606*0Sstevel@tonic-gate 1607*0Sstevel@tonic-gateprint Q<<"EOF"; 1608*0Sstevel@tonic-gate#XS(boot_$Module_cname); /* prototype to pass -Wmissing-prototypes */ 1609*0Sstevel@tonic-gate#XS(boot_$Module_cname) 1610*0Sstevel@tonic-gateEOF 1611*0Sstevel@tonic-gate 1612*0Sstevel@tonic-gateprint Q<<"EOF"; 1613*0Sstevel@tonic-gate#[[ 1614*0Sstevel@tonic-gate# dXSARGS; 1615*0Sstevel@tonic-gateEOF 1616*0Sstevel@tonic-gate 1617*0Sstevel@tonic-gate#-Wall: if there is no $Full_func_name there are no xsubs in this .xs 1618*0Sstevel@tonic-gate#so `file' is unused 1619*0Sstevel@tonic-gateprint Q<<"EOF" if $Full_func_name; 1620*0Sstevel@tonic-gate# char* file = __FILE__; 1621*0Sstevel@tonic-gateEOF 1622*0Sstevel@tonic-gate 1623*0Sstevel@tonic-gateprint Q "#\n"; 1624*0Sstevel@tonic-gate 1625*0Sstevel@tonic-gateprint Q<<"EOF" if $WantVersionChk ; 1626*0Sstevel@tonic-gate# XS_VERSION_BOOTCHECK ; 1627*0Sstevel@tonic-gate# 1628*0Sstevel@tonic-gateEOF 1629*0Sstevel@tonic-gate 1630*0Sstevel@tonic-gateprint Q<<"EOF" if defined $XsubAliases or defined $Interfaces ; 1631*0Sstevel@tonic-gate# { 1632*0Sstevel@tonic-gate# CV * cv ; 1633*0Sstevel@tonic-gate# 1634*0Sstevel@tonic-gateEOF 1635*0Sstevel@tonic-gate 1636*0Sstevel@tonic-gateprint Q<<"EOF" if ($Overload); 1637*0Sstevel@tonic-gate# /* register the overloading (type 'A') magic */ 1638*0Sstevel@tonic-gate# PL_amagic_generation++; 1639*0Sstevel@tonic-gate# /* The magic for overload gets a GV* via gv_fetchmeth as */ 1640*0Sstevel@tonic-gate# /* mentioned above, and looks in the SV* slot of it for */ 1641*0Sstevel@tonic-gate# /* the "fallback" status. */ 1642*0Sstevel@tonic-gate# sv_setsv( 1643*0Sstevel@tonic-gate# get_sv( "${Package}::()", TRUE ), 1644*0Sstevel@tonic-gate# $Fallback 1645*0Sstevel@tonic-gate# ); 1646*0Sstevel@tonic-gateEOF 1647*0Sstevel@tonic-gate 1648*0Sstevel@tonic-gateprint @InitFileCode; 1649*0Sstevel@tonic-gate 1650*0Sstevel@tonic-gateprint Q<<"EOF" if defined $XsubAliases or defined $Interfaces ; 1651*0Sstevel@tonic-gate# } 1652*0Sstevel@tonic-gateEOF 1653*0Sstevel@tonic-gate 1654*0Sstevel@tonic-gateif (@BootCode) 1655*0Sstevel@tonic-gate{ 1656*0Sstevel@tonic-gate print "\n /* Initialisation Section */\n\n" ; 1657*0Sstevel@tonic-gate @line = @BootCode; 1658*0Sstevel@tonic-gate print_section(); 1659*0Sstevel@tonic-gate print "\n /* End of Initialisation Section */\n\n" ; 1660*0Sstevel@tonic-gate} 1661*0Sstevel@tonic-gate 1662*0Sstevel@tonic-gateprint Q<<"EOF";; 1663*0Sstevel@tonic-gate# XSRETURN_YES; 1664*0Sstevel@tonic-gate#]] 1665*0Sstevel@tonic-gate# 1666*0Sstevel@tonic-gateEOF 1667*0Sstevel@tonic-gate 1668*0Sstevel@tonic-gatewarn("Please specify prototyping behavior for $filename (see perlxs manual)\n") 1669*0Sstevel@tonic-gate unless $ProtoUsed ; 1670*0Sstevel@tonic-gate&Exit; 1671*0Sstevel@tonic-gate 1672*0Sstevel@tonic-gatesub output_init { 1673*0Sstevel@tonic-gate local($type, $num, $var, $init, $name_printed) = @_; 1674*0Sstevel@tonic-gate local($arg) = "ST(" . ($num - 1) . ")"; 1675*0Sstevel@tonic-gate 1676*0Sstevel@tonic-gate if( $init =~ /^=/ ) { 1677*0Sstevel@tonic-gate if ($name_printed) { 1678*0Sstevel@tonic-gate eval qq/print " $init\\n"/; 1679*0Sstevel@tonic-gate } else { 1680*0Sstevel@tonic-gate eval qq/print "\\t$var $init\\n"/; 1681*0Sstevel@tonic-gate } 1682*0Sstevel@tonic-gate warn $@ if $@; 1683*0Sstevel@tonic-gate } else { 1684*0Sstevel@tonic-gate if( $init =~ s/^\+// && $num ) { 1685*0Sstevel@tonic-gate &generate_init($type, $num, $var, $name_printed); 1686*0Sstevel@tonic-gate } elsif ($name_printed) { 1687*0Sstevel@tonic-gate print ";\n"; 1688*0Sstevel@tonic-gate $init =~ s/^;//; 1689*0Sstevel@tonic-gate } else { 1690*0Sstevel@tonic-gate eval qq/print "\\t$var;\\n"/; 1691*0Sstevel@tonic-gate warn $@ if $@; 1692*0Sstevel@tonic-gate $init =~ s/^;//; 1693*0Sstevel@tonic-gate } 1694*0Sstevel@tonic-gate $deferred .= eval qq/"\\n\\t$init\\n"/; 1695*0Sstevel@tonic-gate warn $@ if $@; 1696*0Sstevel@tonic-gate } 1697*0Sstevel@tonic-gate} 1698*0Sstevel@tonic-gate 1699*0Sstevel@tonic-gatesub Warn 1700*0Sstevel@tonic-gate{ 1701*0Sstevel@tonic-gate # work out the line number 1702*0Sstevel@tonic-gate my $line_no = $line_no[@line_no - @line -1] ; 1703*0Sstevel@tonic-gate 1704*0Sstevel@tonic-gate print STDERR "@_ in $filename, line $line_no\n" ; 1705*0Sstevel@tonic-gate} 1706*0Sstevel@tonic-gate 1707*0Sstevel@tonic-gatesub blurt 1708*0Sstevel@tonic-gate{ 1709*0Sstevel@tonic-gate Warn @_ ; 1710*0Sstevel@tonic-gate $errors ++ 1711*0Sstevel@tonic-gate} 1712*0Sstevel@tonic-gate 1713*0Sstevel@tonic-gatesub death 1714*0Sstevel@tonic-gate{ 1715*0Sstevel@tonic-gate Warn @_ ; 1716*0Sstevel@tonic-gate exit 1 ; 1717*0Sstevel@tonic-gate} 1718*0Sstevel@tonic-gate 1719*0Sstevel@tonic-gatesub generate_init { 1720*0Sstevel@tonic-gate local($type, $num, $var) = @_; 1721*0Sstevel@tonic-gate local($arg) = "ST(" . ($num - 1) . ")"; 1722*0Sstevel@tonic-gate local($argoff) = $num - 1; 1723*0Sstevel@tonic-gate local($ntype); 1724*0Sstevel@tonic-gate local($tk); 1725*0Sstevel@tonic-gate 1726*0Sstevel@tonic-gate $type = TidyType($type) ; 1727*0Sstevel@tonic-gate blurt("Error: '$type' not in typemap"), return 1728*0Sstevel@tonic-gate unless defined($type_kind{$type}); 1729*0Sstevel@tonic-gate 1730*0Sstevel@tonic-gate ($ntype = $type) =~ s/\s*\*/Ptr/g; 1731*0Sstevel@tonic-gate ($subtype = $ntype) =~ s/(?:Array)?(?:Ptr)?$//; 1732*0Sstevel@tonic-gate $tk = $type_kind{$type}; 1733*0Sstevel@tonic-gate $tk =~ s/OBJ$/REF/ if $func_name =~ /DESTROY$/; 1734*0Sstevel@tonic-gate if ($tk eq 'T_PV' and exists $lengthof{$var}) { 1735*0Sstevel@tonic-gate print "\t$var" unless $name_printed; 1736*0Sstevel@tonic-gate print " = ($type)SvPV($arg, STRLEN_length_of_$var);\n"; 1737*0Sstevel@tonic-gate die "default value not supported with length(NAME) supplied" 1738*0Sstevel@tonic-gate if defined $defaults{$var}; 1739*0Sstevel@tonic-gate return; 1740*0Sstevel@tonic-gate } 1741*0Sstevel@tonic-gate $type =~ tr/:/_/ unless $hiertype; 1742*0Sstevel@tonic-gate blurt("Error: No INPUT definition for type '$type', typekind '$type_kind{$type}' found"), return 1743*0Sstevel@tonic-gate unless defined $input_expr{$tk} ; 1744*0Sstevel@tonic-gate $expr = $input_expr{$tk}; 1745*0Sstevel@tonic-gate if ($expr =~ /DO_ARRAY_ELEM/) { 1746*0Sstevel@tonic-gate blurt("Error: '$subtype' not in typemap"), return 1747*0Sstevel@tonic-gate unless defined($type_kind{$subtype}); 1748*0Sstevel@tonic-gate blurt("Error: No INPUT definition for type '$subtype', typekind '$type_kind{$subtype}' found"), return 1749*0Sstevel@tonic-gate unless defined $input_expr{$type_kind{$subtype}} ; 1750*0Sstevel@tonic-gate $subexpr = $input_expr{$type_kind{$subtype}}; 1751*0Sstevel@tonic-gate $subexpr =~ s/\$type/\$subtype/g; 1752*0Sstevel@tonic-gate $subexpr =~ s/ntype/subtype/g; 1753*0Sstevel@tonic-gate $subexpr =~ s/\$arg/ST(ix_$var)/g; 1754*0Sstevel@tonic-gate $subexpr =~ s/\n\t/\n\t\t/g; 1755*0Sstevel@tonic-gate $subexpr =~ s/is not of (.*\")/[arg %d] is not of $1, ix_$var + 1/g; 1756*0Sstevel@tonic-gate $subexpr =~ s/\$var/${var}[ix_$var - $argoff]/; 1757*0Sstevel@tonic-gate $expr =~ s/DO_ARRAY_ELEM/$subexpr/; 1758*0Sstevel@tonic-gate } 1759*0Sstevel@tonic-gate if ($expr =~ m#/\*.*scope.*\*/#i) { # "scope" in C comments 1760*0Sstevel@tonic-gate $ScopeThisXSUB = 1; 1761*0Sstevel@tonic-gate } 1762*0Sstevel@tonic-gate if (defined($defaults{$var})) { 1763*0Sstevel@tonic-gate $expr =~ s/(\t+)/$1 /g; 1764*0Sstevel@tonic-gate $expr =~ s/ /\t/g; 1765*0Sstevel@tonic-gate if ($name_printed) { 1766*0Sstevel@tonic-gate print ";\n"; 1767*0Sstevel@tonic-gate } else { 1768*0Sstevel@tonic-gate eval qq/print "\\t$var;\\n"/; 1769*0Sstevel@tonic-gate warn $@ if $@; 1770*0Sstevel@tonic-gate } 1771*0Sstevel@tonic-gate if ($defaults{$var} eq 'NO_INIT') { 1772*0Sstevel@tonic-gate $deferred .= eval qq/"\\n\\tif (items >= $num) {\\n$expr;\\n\\t}\\n"/; 1773*0Sstevel@tonic-gate } else { 1774*0Sstevel@tonic-gate $deferred .= eval qq/"\\n\\tif (items < $num)\\n\\t $var = $defaults{$var};\\n\\telse {\\n$expr;\\n\\t}\\n"/; 1775*0Sstevel@tonic-gate } 1776*0Sstevel@tonic-gate warn $@ if $@; 1777*0Sstevel@tonic-gate } elsif ($ScopeThisXSUB or $expr !~ /^\s*\$var =/) { 1778*0Sstevel@tonic-gate if ($name_printed) { 1779*0Sstevel@tonic-gate print ";\n"; 1780*0Sstevel@tonic-gate } else { 1781*0Sstevel@tonic-gate eval qq/print "\\t$var;\\n"/; 1782*0Sstevel@tonic-gate warn $@ if $@; 1783*0Sstevel@tonic-gate } 1784*0Sstevel@tonic-gate $deferred .= eval qq/"\\n$expr;\\n"/; 1785*0Sstevel@tonic-gate warn $@ if $@; 1786*0Sstevel@tonic-gate } else { 1787*0Sstevel@tonic-gate die "panic: do not know how to handle this branch for function pointers" 1788*0Sstevel@tonic-gate if $name_printed; 1789*0Sstevel@tonic-gate eval qq/print "$expr;\\n"/; 1790*0Sstevel@tonic-gate warn $@ if $@; 1791*0Sstevel@tonic-gate } 1792*0Sstevel@tonic-gate} 1793*0Sstevel@tonic-gate 1794*0Sstevel@tonic-gatesub generate_output { 1795*0Sstevel@tonic-gate local($type, $num, $var, $do_setmagic, $do_push) = @_; 1796*0Sstevel@tonic-gate local($arg) = "ST(" . ($num - ($num != 0)) . ")"; 1797*0Sstevel@tonic-gate local($argoff) = $num - 1; 1798*0Sstevel@tonic-gate local($ntype); 1799*0Sstevel@tonic-gate 1800*0Sstevel@tonic-gate $type = TidyType($type) ; 1801*0Sstevel@tonic-gate if ($type =~ /^array\(([^,]*),(.*)\)/) { 1802*0Sstevel@tonic-gate print "\t$arg = sv_newmortal();\n"; 1803*0Sstevel@tonic-gate print "\tsv_setpvn($arg, (char *)$var, $2 * sizeof($1));\n"; 1804*0Sstevel@tonic-gate print "\tSvSETMAGIC($arg);\n" if $do_setmagic; 1805*0Sstevel@tonic-gate } else { 1806*0Sstevel@tonic-gate blurt("Error: '$type' not in typemap"), return 1807*0Sstevel@tonic-gate unless defined($type_kind{$type}); 1808*0Sstevel@tonic-gate blurt("Error: No OUTPUT definition for type '$type', typekind '$type_kind{$type}' found"), return 1809*0Sstevel@tonic-gate unless defined $output_expr{$type_kind{$type}} ; 1810*0Sstevel@tonic-gate ($ntype = $type) =~ s/\s*\*/Ptr/g; 1811*0Sstevel@tonic-gate $ntype =~ s/\(\)//g; 1812*0Sstevel@tonic-gate ($subtype = $ntype) =~ s/(?:Array)?(?:Ptr)?$//; 1813*0Sstevel@tonic-gate $expr = $output_expr{$type_kind{$type}}; 1814*0Sstevel@tonic-gate if ($expr =~ /DO_ARRAY_ELEM/) { 1815*0Sstevel@tonic-gate blurt("Error: '$subtype' not in typemap"), return 1816*0Sstevel@tonic-gate unless defined($type_kind{$subtype}); 1817*0Sstevel@tonic-gate blurt("Error: No OUTPUT definition for type '$subtype', typekind '$type_kind{$subtype}' found"), return 1818*0Sstevel@tonic-gate unless defined $output_expr{$type_kind{$subtype}} ; 1819*0Sstevel@tonic-gate $subexpr = $output_expr{$type_kind{$subtype}}; 1820*0Sstevel@tonic-gate $subexpr =~ s/ntype/subtype/g; 1821*0Sstevel@tonic-gate $subexpr =~ s/\$arg/ST(ix_$var)/g; 1822*0Sstevel@tonic-gate $subexpr =~ s/\$var/${var}[ix_$var]/g; 1823*0Sstevel@tonic-gate $subexpr =~ s/\n\t/\n\t\t/g; 1824*0Sstevel@tonic-gate $expr =~ s/DO_ARRAY_ELEM\n/$subexpr/; 1825*0Sstevel@tonic-gate eval "print qq\a$expr\a"; 1826*0Sstevel@tonic-gate warn $@ if $@; 1827*0Sstevel@tonic-gate print "\t\tSvSETMAGIC(ST(ix_$var));\n" if $do_setmagic; 1828*0Sstevel@tonic-gate } 1829*0Sstevel@tonic-gate elsif ($var eq 'RETVAL') { 1830*0Sstevel@tonic-gate if ($expr =~ /^\t\$arg = new/) { 1831*0Sstevel@tonic-gate # We expect that $arg has refcnt 1, so we need to 1832*0Sstevel@tonic-gate # mortalize it. 1833*0Sstevel@tonic-gate eval "print qq\a$expr\a"; 1834*0Sstevel@tonic-gate warn $@ if $@; 1835*0Sstevel@tonic-gate print "\tsv_2mortal(ST($num));\n"; 1836*0Sstevel@tonic-gate print "\tSvSETMAGIC(ST($num));\n" if $do_setmagic; 1837*0Sstevel@tonic-gate } 1838*0Sstevel@tonic-gate elsif ($expr =~ /^\s*\$arg\s*=/) { 1839*0Sstevel@tonic-gate # We expect that $arg has refcnt >=1, so we need 1840*0Sstevel@tonic-gate # to mortalize it! 1841*0Sstevel@tonic-gate eval "print qq\a$expr\a"; 1842*0Sstevel@tonic-gate warn $@ if $@; 1843*0Sstevel@tonic-gate print "\tsv_2mortal(ST(0));\n"; 1844*0Sstevel@tonic-gate print "\tSvSETMAGIC(ST(0));\n" if $do_setmagic; 1845*0Sstevel@tonic-gate } 1846*0Sstevel@tonic-gate else { 1847*0Sstevel@tonic-gate # Just hope that the entry would safely write it 1848*0Sstevel@tonic-gate # over an already mortalized value. By 1849*0Sstevel@tonic-gate # coincidence, something like $arg = &sv_undef 1850*0Sstevel@tonic-gate # works too. 1851*0Sstevel@tonic-gate print "\tST(0) = sv_newmortal();\n"; 1852*0Sstevel@tonic-gate eval "print qq\a$expr\a"; 1853*0Sstevel@tonic-gate warn $@ if $@; 1854*0Sstevel@tonic-gate # new mortals don't have set magic 1855*0Sstevel@tonic-gate } 1856*0Sstevel@tonic-gate } 1857*0Sstevel@tonic-gate elsif ($do_push) { 1858*0Sstevel@tonic-gate print "\tPUSHs(sv_newmortal());\n"; 1859*0Sstevel@tonic-gate $arg = "ST($num)"; 1860*0Sstevel@tonic-gate eval "print qq\a$expr\a"; 1861*0Sstevel@tonic-gate warn $@ if $@; 1862*0Sstevel@tonic-gate print "\tSvSETMAGIC($arg);\n" if $do_setmagic; 1863*0Sstevel@tonic-gate } 1864*0Sstevel@tonic-gate elsif ($arg =~ /^ST\(\d+\)$/) { 1865*0Sstevel@tonic-gate eval "print qq\a$expr\a"; 1866*0Sstevel@tonic-gate warn $@ if $@; 1867*0Sstevel@tonic-gate print "\tSvSETMAGIC($arg);\n" if $do_setmagic; 1868*0Sstevel@tonic-gate } 1869*0Sstevel@tonic-gate } 1870*0Sstevel@tonic-gate} 1871*0Sstevel@tonic-gate 1872*0Sstevel@tonic-gatesub map_type { 1873*0Sstevel@tonic-gate my($type, $varname) = @_; 1874*0Sstevel@tonic-gate 1875*0Sstevel@tonic-gate # C++ has :: in types too so skip this 1876*0Sstevel@tonic-gate $type =~ tr/:/_/ unless $hiertype; 1877*0Sstevel@tonic-gate $type =~ s/^array\(([^,]*),(.*)\).*/$1 */s; 1878*0Sstevel@tonic-gate if ($varname) { 1879*0Sstevel@tonic-gate if ($varname && $type =~ / \( \s* \* (?= \s* \) ) /xg) { 1880*0Sstevel@tonic-gate (substr $type, pos $type, 0) = " $varname "; 1881*0Sstevel@tonic-gate } else { 1882*0Sstevel@tonic-gate $type .= "\t$varname"; 1883*0Sstevel@tonic-gate } 1884*0Sstevel@tonic-gate } 1885*0Sstevel@tonic-gate $type; 1886*0Sstevel@tonic-gate} 1887*0Sstevel@tonic-gate 1888*0Sstevel@tonic-gate 1889*0Sstevel@tonic-gatesub Exit { 1890*0Sstevel@tonic-gate# If this is VMS, the exit status has meaning to the shell, so we 1891*0Sstevel@tonic-gate# use a predictable value (SS$_Normal or SS$_Abort) rather than an 1892*0Sstevel@tonic-gate# arbitrary number. 1893*0Sstevel@tonic-gate# exit ($Is_VMS ? ($errors ? 44 : 1) : $errors) ; 1894*0Sstevel@tonic-gate exit ($errors ? 1 : 0); 1895*0Sstevel@tonic-gate} 1896