Move Devel::PPPort from ext/ to cpan/
[p5sagit/p5-mst-13.2.git] / cpan / Devel-PPPort / parts / apicheck.pl
1 #!/usr/bin/perl -w
2 ################################################################################
3 #
4 #  apicheck.pl -- generate C source for automated API check
5 #
6 ################################################################################
7 #
8 #  $Revision: 35 $
9 #  $Author: mhx $
10 #  $Date: 2009/06/12 12:29:35 +0200 $
11 #
12 ################################################################################
13 #
14 #  Version 3.x, Copyright (C) 2004-2009, Marcus Holland-Moritz.
15 #  Version 2.x, Copyright (C) 2001, Paul Marquess.
16 #  Version 1.x, Copyright (C) 1999, Kenneth Albanowski.
17 #
18 #  This program is free software; you can redistribute it and/or
19 #  modify it under the same terms as Perl itself.
20 #
21 ################################################################################
22
23 use strict;
24 require 'parts/ppptools.pl';
25
26 if (@ARGV) {
27   my $file = pop @ARGV;
28   open OUT, ">$file" or die "$file: $!\n";
29 }
30 else {
31   *OUT = \*STDOUT;
32 }
33
34 my @f = parse_embed(qw( parts/embed.fnc parts/apidoc.fnc parts/ppport.fnc ));
35
36 my %todo = %{&parse_todo};
37
38 my %tmap = (
39   void => 'int',
40 );
41
42 my %amap = (
43   SP   => 'SP',
44   type => 'int',
45   cast => 'int',
46 );
47
48 my %void = (
49   void     => 1,
50   Free_t   => 1,
51   Signal_t => 1,
52 );
53
54 my %castvoid = (
55   map { ($_ => 1) } qw(
56     Nullav
57     Nullcv
58     Nullhv
59     Nullch
60     Nullsv
61     HEf_SVKEY
62     SP
63     MARK
64     SVt_PV
65     SVt_IV
66     SVt_NV
67     SVt_PVMG
68     SVt_PVAV
69     SVt_PVHV
70     SVt_PVCV
71     SvUOK
72     G_SCALAR
73     G_ARRAY
74     G_VOID
75     G_DISCARD
76     G_EVAL
77     G_NOARGS
78     XS_VERSION
79   ),
80 );
81
82 my %ignorerv = (
83   map { ($_ => 1) } qw(
84     newCONSTSUB
85   ),
86 );
87
88 my %stack = (
89   ORIGMARK       => ['dORIGMARK;'],
90   POPpx          => ['STRLEN n_a;'],
91   POPpbytex      => ['STRLEN n_a;'],
92   PUSHp          => ['dTARG;'],
93   PUSHn          => ['dTARG;'],
94   PUSHi          => ['dTARG;'],
95   PUSHu          => ['dTARG;'],
96   XPUSHp         => ['dTARG;'],
97   XPUSHn         => ['dTARG;'],
98   XPUSHi         => ['dTARG;'],
99   XPUSHu         => ['dTARG;'],
100   UNDERBAR       => ['dUNDERBAR;'],
101   XCPT_TRY_START => ['dXCPT;'],
102   XCPT_TRY_END   => ['dXCPT;'],
103   XCPT_CATCH     => ['dXCPT;'],
104   XCPT_RETHROW   => ['dXCPT;'],
105 );
106
107 my %ignore = (
108   map { ($_ => 1) } qw(
109     svtype
110     items
111     ix
112     dXSI32
113     XS
114     CLASS
115     THIS
116     RETVAL
117     StructCopy
118   ),
119 );
120
121 print OUT <<HEAD;
122 /*
123  * !!!!!!!   DO NOT EDIT THIS FILE   !!!!!!!
124  * This file is built by $0.
125  * Any changes made here will be lost!
126  */
127
128 #include "EXTERN.h"
129 #include "perl.h"
130
131 #define NO_XSLOCKS
132 #include "XSUB.h"
133
134 #ifdef DPPP_APICHECK_NO_PPPORT_H
135
136 /* This is just to avoid too many baseline failures with perls < 5.6.0 */
137
138 #ifndef dTHX
139 #  define dTHX extern int Perl___notused
140 #endif
141
142 #else
143
144 #define NEED_PL_signals
145 #define NEED_PL_parser
146 #define NEED_eval_pv
147 #define NEED_grok_bin
148 #define NEED_grok_hex
149 #define NEED_grok_number
150 #define NEED_grok_numeric_radix
151 #define NEED_grok_oct
152 #define NEED_load_module
153 #define NEED_my_snprintf
154 #define NEED_my_sprintf
155 #define NEED_my_strlcat
156 #define NEED_my_strlcpy
157 #define NEED_newCONSTSUB
158 #define NEED_newRV_noinc
159 #define NEED_newSV_type
160 #define NEED_newSVpvn_share
161 #define NEED_pv_display
162 #define NEED_pv_escape
163 #define NEED_pv_pretty
164 #define NEED_sv_2pv_flags
165 #define NEED_sv_2pvbyte
166 #define NEED_sv_catpvf_mg
167 #define NEED_sv_catpvf_mg_nocontext
168 #define NEED_sv_pvn_force_flags
169 #define NEED_sv_setpvf_mg
170 #define NEED_sv_setpvf_mg_nocontext
171 #define NEED_vload_module
172 #define NEED_vnewSVpvf
173 #define NEED_warner
174 #define NEED_newSVpvn_flags
175
176 #include "ppport.h"
177
178 #endif
179
180 static int    VARarg1;
181 static char  *VARarg2;
182 static double VARarg3;
183
184 HEAD
185
186 if (@ARGV) {
187   my %want = map { ($_ => 0) } @ARGV;
188   @f = grep { exists $want{$_->{name}} } @f;
189   for (@f) { $want{$_->{name}}++ }
190   for (keys %want) {
191     die "nothing found for '$_'\n" unless $want{$_};
192   }
193 }
194
195 my $f;
196 for $f (@f) {
197   $ignore{$f->{name}} and next;
198   $f->{flags}{A} or next;  # only public API members
199
200   $ignore{$f->{name}} = 1; # ignore duplicates
201
202   my $Perl_ = $f->{flags}{p} ? 'Perl_' : '';
203
204   my $stack = '';
205   my @arg;
206   my $aTHX = '';
207
208   my $i = 1;
209   my $ca;
210   my $varargs = 0;
211   for $ca (@{$f->{args}}) {
212     my $a = $ca->[0];
213     if ($a eq '...') {
214       $varargs = 1;
215       push @arg, qw(VARarg1 VARarg2 VARarg3);
216       last;
217     }
218     my($n, $p, $d) = $a =~ /^ (\w+(?:\s+\w+)*)\s*  # type name  => $n
219                               (\**)                # pointer    => $p
220                               (?:\s*const\s*)?     # const
221                               ((?:\[[^\]]*\])*)    # dimension  => $d
222                             $/x
223                      or die "$0 - cannot parse argument: [$a]\n";
224     if (exists $amap{$n}) {
225       push @arg, $amap{$n};
226       next;
227     }
228     $n = $tmap{$n} || $n;
229     if ($n eq 'const char' and $p eq '*' and !$f->{flags}{f}) {
230       push @arg, '"foo"';
231     }
232     else {
233       my $v = 'arg' . $i++;
234       push @arg, $v;
235       $stack .= "  static $n $p$v$d;\n";
236     }
237   }
238
239   unless ($f->{flags}{n} || $f->{flags}{'m'}) {
240     $stack = "  dTHX;\n$stack";
241     $aTHX = @arg ? 'aTHX_ ' : 'aTHX';
242   }
243
244   if ($stack{$f->{name}}) {
245     my $s = '';
246     for (@{$stack{$f->{name}}}) {
247       $s .= "  $_\n";
248     }
249     $stack = "$s$stack";
250   }
251
252   my $args = join ', ', @arg;
253   my $rvt = $f->{ret} || 'void';
254   my $ret;
255   if ($void{$rvt}) {
256     $ret = $castvoid{$f->{name}} ? '(void) ' : '';
257   }
258   else {
259     $stack .= "  $rvt rval;\n";
260     $ret = $ignorerv{$f->{name}} ? '(void) ' : "rval = ";
261   }
262   my $aTHX_args = "$aTHX$args";
263
264   unless ($f->{flags}{'m'} and @arg == 0) {
265     $args = "($args)";
266     $aTHX_args = "($aTHX_args)";
267   }
268
269   print OUT <<HEAD;
270 /******************************************************************************
271 *
272 *  $f->{name}
273 *
274 ******************************************************************************/
275
276 HEAD
277
278   if ($todo{$f->{name}}) {
279     my($ver,$sub) = $todo{$f->{name}} =~ /^5\.(\d{3})(\d{3})$/ or die;
280     for ($ver, $sub) {
281       s/^0+(\d)/$1/
282     }
283     if ($ver < 6 && $sub > 0) {
284       $sub =~ s/0$// or die;
285     }
286     print OUT "#if PERL_VERSION > $ver || (PERL_VERSION == $ver && PERL_SUBVERSION >= $sub) /* TODO */\n";
287   }
288
289   my $final = $varargs
290               ? "$Perl_$f->{name}$aTHX_args"
291               : "$f->{name}$args";
292
293   $f->{cond} and print OUT "#if $f->{cond}\n";
294
295   print OUT <<END;
296 void _DPPP_test_$f->{name} (void)
297 {
298   dXSARGS;
299 $stack
300   {
301 #ifdef $f->{name}
302     $ret$f->{name}$args;
303 #endif
304   }
305
306   {
307 #ifdef $f->{name}
308     $ret$final;
309 #else
310     $ret$Perl_$f->{name}$aTHX_args;
311 #endif
312   }
313 }
314 END
315
316   $f->{cond} and print OUT "#endif\n";
317   $todo{$f->{name}} and print OUT "#endif\n";
318
319   print OUT "\n";
320 }
321
322 @ARGV and close OUT;
323