2 ################################################################################
4 # apicheck.pl -- generate apicheck.c: C source for automated API check
6 # WARNING: This script will be run on very old perls. You need to not use
7 # modern constructs. See HACKERS file for examples.
9 ################################################################################
11 # Version 3.x, Copyright (C) 2004-2013, Marcus Holland-Moritz.
12 # Version 2.x, Copyright (C) 2001, Paul Marquess.
13 # Version 1.x, Copyright (C) 1999, Kenneth Albanowski.
15 # This program is free software; you can redistribute it and/or
16 # modify it under the same terms as Perl itself.
18 ################################################################################
21 require './parts/ppptools.pl';
25 open OUT, ">$file" or die "$file: $!\n";
31 # Get list of functions/macros to test
32 my @f = parse_embed(qw( parts/embed.fnc parts/apidoc.fnc parts/ppport.fnc ));
34 # Read in what we've decided in previous calls should be #ifdef'd out for this
35 # call. The keys are the symbols to test; each value is a subhash, like so:
36 # 'utf8_hop_forward' => {
37 # 'version' => '5.025007'
39 # We don't care here about other subkeys
40 my %todo = %{&parse_todo};
42 # We convert these types into these other types
47 # These are for special marker argument names, as mentioned in embed.fnc
55 # Certain return types are instead considered void
62 # khw doesn't know why these exist. These have an explicit (void) cast added.
63 # Undef'ing this hash made no difference. Maybe it's for older compilers?
92 # Ignore the return value of these
99 my @simple_my_cxt_prereqs = ( 'typedef struct { int count; } my_cxt_t;', 'START_MY_CXT;' );
100 my @my_cxt_prereqs = ( @simple_my_cxt_prereqs, 'MY_CXT_INIT;' );
102 # The value of each key is a list of things that need to be declared in order
103 # for the key to compile.
105 MULTICALL => ['dMULTICALL;'],
106 ORIGMARK => ['dORIGMARK;'],
107 POP_MULTICALL => ['dMULTICALL;', 'U8 gimme;' ],
108 PUSH_MULTICALL => ['dMULTICALL;', 'U8 gimme;' ],
109 POPpbytex => ['STRLEN n_a;'],
110 POPpx => ['STRLEN n_a;'],
115 RESTORE_LC_NUMERIC => ['DECLARATION_FOR_LC_NUMERIC_MANIPULATION;'],
116 STORE_LC_NUMERIC_FORCE_TO_UNDERLYING => ['DECLARATION_FOR_LC_NUMERIC_MANIPULATION;'],
117 STORE_LC_NUMERIC_SET_TO_NEEDED => ['DECLARATION_FOR_LC_NUMERIC_MANIPULATION;'],
118 STORE_LC_NUMERIC_SET_TO_NEEDED_IN => ['DECLARATION_FOR_LC_NUMERIC_MANIPULATION;'],
119 UNDERBAR => ['dUNDERBAR;'],
120 XCPT_CATCH => ['dXCPT;'],
121 XCPT_RETHROW => ['dXCPT;'],
122 XCPT_TRY_END => ['dXCPT;'],
123 XCPT_TRY_START => ['dXCPT;'],
124 XPUSHi => ['dTARG;'],
125 XPUSHn => ['dTARG;'],
126 XPUSHp => ['dTARG;'],
127 XPUSHu => ['dTARG;'],
128 XS_APIVERSION_BOOTCHECK => ['CV * cv;'],
129 XS_VERSION_BOOTCHECK => ['CV * cv;'],
130 MY_CXT_INIT => [ @simple_my_cxt_prereqs ],
131 MY_CXT_CLONE => [ @simple_my_cxt_prereqs ],
132 dMY_CXT => [ @simple_my_cxt_prereqs ],
133 MY_CXT => [ @my_cxt_prereqs ],
134 _aMY_CXT => [ @my_cxt_prereqs ],
135 aMY_CXT => [ @my_cxt_prereqs ],
136 aMY_CXT_ => [ @my_cxt_prereqs ],
137 pMY_CXT => [ @my_cxt_prereqs ],
141 # Things to not try to check.
142 my %ignore = map { ("$_" => 1) } keys %{&known_but_hard_to_test_for()};
144 # XXX The NEED_foo lines should be autogenerated
147 * !!!!!!! DO NOT EDIT THIS FILE !!!!!!!
148 * This file is built by $0.
149 * Any changes made here will be lost!
158 #ifdef DPPP_APICHECK_NO_PPPORT_H
160 /* This is just to avoid too many baseline failures with perls < 5.6.0 */
163 # define dTHX extern int Perl___notused
168 #define NEED_PL_parser
169 #define NEED_PL_signals
170 #define NEED_caller_cx
171 #define NEED_croak_xs_usage
174 #define NEED_grok_bin
175 #define NEED_grok_hex
176 #define NEED_grok_number
177 #define NEED_grok_numeric_radix
178 #define NEED_grok_oct
179 #define NEED_load_module
181 #define NEED_mess_nocontext
183 #define NEED_mg_findext
184 #define NEED_my_snprintf
185 #define NEED_my_sprintf
186 #define NEED_my_strlcat
187 #define NEED_my_strlcpy
188 #define NEED_my_strnlen
189 #define NEED_newCONSTSUB
190 #define NEED_newSVpvn_share
191 #define NEED_pv_display
192 #define NEED_pv_escape
193 #define NEED_pv_pretty
194 #define NEED_sv_catpvf_mg
195 #define NEED_sv_catpvf_mg_nocontext
196 #define NEED_sv_setpvf_mg
197 #define NEED_sv_setpvf_mg_nocontext
198 #define NEED_sv_unmagicext
199 #define NEED_utf8_to_uvchr_buf
200 #define NEED_vload_module
209 static char *VARarg2;
210 static double VARarg3;
212 #if defined(PERL_BCDVERSION) && (PERL_BCDVERSION < 0x5009005)
213 /* needed to make PL_parser apicheck work */
214 typedef void yy_parser;
219 # Caller can restrict what functions tests are generated for
221 my %want = map { ($_ => 0) } @ARGV;
222 @f = grep { exists $want{$_->{'name'}} } @f;
223 for (@f) { $want{$_->{'name'}}++ }
225 die "nothing found for '$_'\n" unless $want{$_};
230 for $f (@f) { # Loop through all the tests to add
231 $ignore{$f->{'name'}} and next;
232 $f->{'flags'}{'A'} or next; # only public API members
234 $ignore{$f->{'name'}} = 1; # ignore duplicates
236 my $Perl_ = $f->{'flags'}{'p'} ? 'Perl_' : '';
246 for $ca (@{$f->{'args'}}) { # Loop through the function's args
247 my $a = $ca->[0]; # 1th is the name, 0th is its type
250 push @arg, qw(VARarg1 VARarg2 VARarg3);
254 # Split this type into its components
255 my($n, $p, $d) = $a =~ /^ ( (?: " [^"]* " ) # literal string type => $n
256 | (?: \w+ (?: \s+ \w+ )* ) # name of type => $n
259 ( \** ) # optional pointer(s) => $p
260 (?: \s* \b const \b \s* )? # opt. const
261 ( (?: \[ [^\]]* \] )* ) # opt. dimension(s)=> $d
263 or die "$0 - cannot parse argument: [$a] in $f->{'name'}\n";
265 # Replace a special argument name by something that will compile.
266 if (exists $amap{$n}) {
267 die "$f->{'name'} had type $n, which should have been the whole type"
269 push @arg, $amap{$n};
273 # Certain types, like 'void', get remapped.
274 $n = $tmap{$n} || $n;
276 if ($n =~ / ^ " [^"]* " $/x) { # Use the literal string, literally
280 my $v = 'arg' . $i++; # Argument number
282 my $no_const_n = $n; # Get rid of any remaining 'const's
283 $no_const_n =~ s/\bconst\b// unless $p;
285 # Declare this argument
286 $stack .= " static $no_const_n $p$v$d;\n";
290 # Declare thread context for functions and macros that might need it.
291 # (Macros often fail to say they don't need it.)
292 unless ($f->{'flags'}{'T'}) {
293 $stack = " dTHX;\n$stack"; # Harmless to declare even if not needed
294 $aTHX = @arg ? 'aTHX_ ' : 'aTHX';
297 # If this function is on the list of things that need declarations, add
299 if ($stack{$f->{'name'}}) {
301 for (@{$stack{$f->{'name'}}}) {
307 my $args = join ', ', @arg;
310 # Failure to specify a return type in the apidoc line means void
311 my $rvt = $f->{'ret'} || 'void';
314 if ($void{$rvt}) { # Certain return types are instead considered void
315 $ret = $castvoid{$f->{'name'}} ? '(void) ' : '';
318 $stack .= " $rvt rval;\n";
319 $ret = $ignorerv{$f->{'name'}} ? '(void) ' : "rval = ";
323 my $aTHX_prefix = "";
325 # Add parens to functions that take an argument list, even if empty
326 unless ($f->{'flags'}{'n'}) {
327 $aTHX_args = "($aTHX$args)";
331 # Single trailing underscore in name means is a comma operator
332 if ($f->{'name'} =~ /[^_]_$/) {
338 /******************************************************************************
342 ******************************************************************************/
346 # #ifdef out if marked as todo (not known in) this version
347 if ($todo{$f->{'name'}}) {
348 my($five, $ver,$sub) = parse_version($todo{$f->{'name'}});
349 print OUT "#if PERL_VERSION > $ver || (PERL_VERSION == $ver && PERL_SUBVERSION >= $sub) /* TODO */\n";
353 ? "$aTHX_prefix$Perl_$f->{'name'}$aTHX_args"
354 : "$prefix$f->{'name'}$args";
356 # If there is a '#if' associated with this, add that
357 $f->{'cond'} and print OUT "#if $f->{'cond'}\n";
360 void _DPPP_test_$f->{'name'} (void)
366 $ret$prefix$f->{'name'}$args;
374 $ret$aTHX_prefix$Perl_$f->{'name'}$aTHX_args;
380 $f->{'cond'} and print OUT "#endif\n";
381 $todo{$f->{'name'}} and print OUT "#endif\n";