Blame parts/apicheck.pl

Packit 7d6a7d
#!/usr/bin/perl -w
Packit 7d6a7d
################################################################################
Packit 7d6a7d
#
Packit 7d6a7d
#  apicheck.pl -- generate C source for automated API check
Packit 7d6a7d
#
Packit 7d6a7d
################################################################################
Packit 7d6a7d
#
Packit 7d6a7d
#  Version 3.x, Copyright (C) 2004-2013, Marcus Holland-Moritz.
Packit 7d6a7d
#  Version 2.x, Copyright (C) 2001, Paul Marquess.
Packit 7d6a7d
#  Version 1.x, Copyright (C) 1999, Kenneth Albanowski.
Packit 7d6a7d
#
Packit 7d6a7d
#  This program is free software; you can redistribute it and/or
Packit 7d6a7d
#  modify it under the same terms as Perl itself.
Packit 7d6a7d
#
Packit 7d6a7d
################################################################################
Packit 7d6a7d
Packit 7d6a7d
use strict;
Packit 7d6a7d
require './parts/ppptools.pl';
Packit 7d6a7d
Packit 7d6a7d
if (@ARGV) {
Packit 7d6a7d
  my $file = pop @ARGV;
Packit 7d6a7d
  open OUT, ">$file" or die "$file: $!\n";
Packit 7d6a7d
}
Packit 7d6a7d
else {
Packit 7d6a7d
  *OUT = \*STDOUT;
Packit 7d6a7d
}
Packit 7d6a7d
Packit 7d6a7d
my @f = parse_embed(qw( parts/embed.fnc parts/apidoc.fnc parts/ppport.fnc ));
Packit 7d6a7d
Packit 7d6a7d
my %todo = %{&parse_todo};
Packit 7d6a7d
Packit 7d6a7d
my %tmap = (
Packit 7d6a7d
  void => 'int',
Packit 7d6a7d
);
Packit 7d6a7d
Packit 7d6a7d
my %amap = (
Packit 7d6a7d
  SP   => 'SP',
Packit 7d6a7d
  type => 'int',
Packit 7d6a7d
  cast => 'int',
Packit 7d6a7d
);
Packit 7d6a7d
Packit 7d6a7d
my %void = (
Packit 7d6a7d
  void     => 1,
Packit 7d6a7d
  Free_t   => 1,
Packit 7d6a7d
  Signal_t => 1,
Packit 7d6a7d
);
Packit 7d6a7d
Packit 7d6a7d
my %castvoid = (
Packit 7d6a7d
  map { ($_ => 1) } qw(
Packit 7d6a7d
    Nullav
Packit 7d6a7d
    Nullcv
Packit 7d6a7d
    Nullhv
Packit 7d6a7d
    Nullch
Packit 7d6a7d
    Nullsv
Packit 7d6a7d
    HEf_SVKEY
Packit 7d6a7d
    SP
Packit 7d6a7d
    MARK
Packit 7d6a7d
    SVt_PV
Packit 7d6a7d
    SVt_IV
Packit 7d6a7d
    SVt_NV
Packit 7d6a7d
    SVt_PVMG
Packit 7d6a7d
    SVt_PVAV
Packit 7d6a7d
    SVt_PVHV
Packit 7d6a7d
    SVt_PVCV
Packit 7d6a7d
    SvUOK
Packit 7d6a7d
    G_SCALAR
Packit 7d6a7d
    G_ARRAY
Packit 7d6a7d
    G_VOID
Packit 7d6a7d
    G_DISCARD
Packit 7d6a7d
    G_EVAL
Packit 7d6a7d
    G_NOARGS
Packit 7d6a7d
    XS_VERSION
Packit 7d6a7d
  ),
Packit 7d6a7d
);
Packit 7d6a7d
Packit 7d6a7d
my %ignorerv = (
Packit 7d6a7d
  map { ($_ => 1) } qw(
Packit 7d6a7d
    newCONSTSUB
Packit 7d6a7d
  ),
Packit 7d6a7d
);
Packit 7d6a7d
Packit 7d6a7d
my %stack = (
Packit 7d6a7d
  ORIGMARK       => ['dORIGMARK;'],
Packit 7d6a7d
  POPpx          => ['STRLEN n_a;'],
Packit 7d6a7d
  POPpbytex      => ['STRLEN n_a;'],
Packit 7d6a7d
  PUSHp          => ['dTARG;'],
Packit 7d6a7d
  PUSHn          => ['dTARG;'],
Packit 7d6a7d
  PUSHi          => ['dTARG;'],
Packit 7d6a7d
  PUSHu          => ['dTARG;'],
Packit 7d6a7d
  XPUSHp         => ['dTARG;'],
Packit 7d6a7d
  XPUSHn         => ['dTARG;'],
Packit 7d6a7d
  XPUSHi         => ['dTARG;'],
Packit 7d6a7d
  XPUSHu         => ['dTARG;'],
Packit 7d6a7d
  UNDERBAR       => ['dUNDERBAR;'],
Packit 7d6a7d
  XCPT_TRY_START => ['dXCPT;'],
Packit 7d6a7d
  XCPT_TRY_END   => ['dXCPT;'],
Packit 7d6a7d
  XCPT_CATCH     => ['dXCPT;'],
Packit 7d6a7d
  XCPT_RETHROW   => ['dXCPT;'],
Packit 7d6a7d
);
Packit 7d6a7d
Packit 7d6a7d
my %ignore = (
Packit 7d6a7d
  map { ($_ => 1) } qw(
Packit 7d6a7d
    svtype
Packit 7d6a7d
    items
Packit 7d6a7d
    ix
Packit 7d6a7d
    dXSI32
Packit 7d6a7d
    XS
Packit 7d6a7d
    CLASS
Packit 7d6a7d
    THIS
Packit 7d6a7d
    RETVAL
Packit 7d6a7d
    StructCopy
Packit 7d6a7d
  ),
Packit 7d6a7d
);
Packit 7d6a7d
Packit 7d6a7d
print OUT <
Packit 7d6a7d
/*
Packit 7d6a7d
 * !!!!!!!   DO NOT EDIT THIS FILE   !!!!!!!
Packit 7d6a7d
 * This file is built by $0.
Packit 7d6a7d
 * Any changes made here will be lost!
Packit 7d6a7d
 */
Packit 7d6a7d
Packit 7d6a7d
#include "EXTERN.h"
Packit 7d6a7d
#include "perl.h"
Packit 7d6a7d
Packit 7d6a7d
#define NO_XSLOCKS
Packit 7d6a7d
#include "XSUB.h"
Packit 7d6a7d
Packit 7d6a7d
#ifdef DPPP_APICHECK_NO_PPPORT_H
Packit 7d6a7d
Packit 7d6a7d
/* This is just to avoid too many baseline failures with perls < 5.6.0 */
Packit 7d6a7d
Packit 7d6a7d
#ifndef dTHX
Packit 7d6a7d
#  define dTHX extern int Perl___notused
Packit 7d6a7d
#endif
Packit 7d6a7d
Packit 7d6a7d
#else
Packit 7d6a7d
Packit 7d6a7d
#define NEED_PL_signals
Packit 7d6a7d
#define NEED_PL_parser
Packit 7d6a7d
#define NEED_caller_cx
Packit 7d6a7d
#define NEED_eval_pv
Packit 7d6a7d
#define NEED_grok_bin
Packit 7d6a7d
#define NEED_grok_hex
Packit 7d6a7d
#define NEED_grok_number
Packit 7d6a7d
#define NEED_grok_numeric_radix
Packit 7d6a7d
#define NEED_grok_oct
Packit 7d6a7d
#define NEED_gv_fetchpvn_flags
Packit 7d6a7d
#define NEED_load_module
Packit 7d6a7d
#define NEED_mg_findext
Packit 7d6a7d
#define NEED_my_snprintf
Packit 7d6a7d
#define NEED_my_sprintf
Packit 7d6a7d
#define NEED_my_strlcat
Packit 7d6a7d
#define NEED_my_strlcpy
Packit 7d6a7d
#define NEED_newCONSTSUB
Packit 7d6a7d
#define NEED_newRV_noinc
Packit 7d6a7d
#define NEED_newSV_type
Packit 7d6a7d
#define NEED_newSVpvn_flags
Packit 7d6a7d
#define NEED_newSVpvn_share
Packit 7d6a7d
#define NEED_pv_display
Packit 7d6a7d
#define NEED_pv_escape
Packit 7d6a7d
#define NEED_pv_pretty
Packit 7d6a7d
#define NEED_sv_2pv_flags
Packit 7d6a7d
#define NEED_sv_2pvbyte
Packit 7d6a7d
#define NEED_sv_catpvf_mg
Packit 7d6a7d
#define NEED_sv_catpvf_mg_nocontext
Packit 7d6a7d
#define NEED_sv_pvn_force_flags
Packit 7d6a7d
#define NEED_sv_setpvf_mg
Packit 7d6a7d
#define NEED_sv_setpvf_mg_nocontext
Packit 7d6a7d
#define NEED_sv_unmagicext
Packit 7d6a7d
#define NEED_SvRX
Packit 7d6a7d
#define NEED_vload_module
Packit 7d6a7d
#define NEED_vnewSVpvf
Packit 7d6a7d
#define NEED_warner
Packit 7d6a7d
Packit 7d6a7d
#include "ppport.h"
Packit 7d6a7d
Packit 7d6a7d
#endif
Packit 7d6a7d
Packit 7d6a7d
static int    VARarg1;
Packit 7d6a7d
static char  *VARarg2;
Packit 7d6a7d
static double VARarg3;
Packit 7d6a7d
Packit 7d6a7d
#if defined(PERL_BCDVERSION) && (PERL_BCDVERSION < 0x5009005)
Packit 7d6a7d
/* needed to make PL_parser apicheck work */
Packit 7d6a7d
typedef void yy_parser;
Packit 7d6a7d
#endif
Packit 7d6a7d
Packit 7d6a7d
HEAD
Packit 7d6a7d
Packit 7d6a7d
if (@ARGV) {
Packit 7d6a7d
  my %want = map { ($_ => 0) } @ARGV;
Packit 7d6a7d
  @f = grep { exists $want{$_->{name}} } @f;
Packit 7d6a7d
  for (@f) { $want{$_->{name}}++ }
Packit 7d6a7d
  for (keys %want) {
Packit 7d6a7d
    die "nothing found for '$_'\n" unless $want{$_};
Packit 7d6a7d
  }
Packit 7d6a7d
}
Packit 7d6a7d
Packit 7d6a7d
my $f;
Packit 7d6a7d
for $f (@f) {
Packit 7d6a7d
  $ignore{$f->{name}} and next;
Packit 7d6a7d
  $f->{flags}{A} or next;  # only public API members
Packit 7d6a7d
Packit 7d6a7d
  $ignore{$f->{name}} = 1; # ignore duplicates
Packit 7d6a7d
Packit 7d6a7d
  my $Perl_ = $f->{flags}{p} ? 'Perl_' : '';
Packit 7d6a7d
Packit 7d6a7d
  my $stack = '';
Packit 7d6a7d
  my @arg;
Packit 7d6a7d
  my $aTHX = '';
Packit 7d6a7d
Packit 7d6a7d
  my $i = 1;
Packit 7d6a7d
  my $ca;
Packit 7d6a7d
  my $varargs = 0;
Packit 7d6a7d
  for $ca (@{$f->{args}}) {
Packit 7d6a7d
    my $a = $ca->[0];
Packit 7d6a7d
    if ($a eq '...') {
Packit 7d6a7d
      $varargs = 1;
Packit 7d6a7d
      push @arg, qw(VARarg1 VARarg2 VARarg3);
Packit 7d6a7d
      last;
Packit 7d6a7d
    }
Packit 7d6a7d
    my($n, $p, $d) = $a =~ /^ (\w+(?:\s+\w+)*)\s*  # type name  => $n
Packit 7d6a7d
                              (\**)                # pointer    => $p
Packit 7d6a7d
                              (?:\s*const\s*)?     # const
Packit 7d6a7d
                              ((?:\[[^\]]*\])*)    # dimension  => $d
Packit 7d6a7d
                            $/x
Packit 7d6a7d
                     or die "$0 - cannot parse argument: [$a]\n";
Packit 7d6a7d
    if (exists $amap{$n}) {
Packit 7d6a7d
      push @arg, $amap{$n};
Packit 7d6a7d
      next;
Packit 7d6a7d
    }
Packit 7d6a7d
    $n = $tmap{$n} || $n;
Packit 7d6a7d
    if ($n eq 'const char' and $p eq '*' and !$f->{flags}{f}) {
Packit 7d6a7d
      push @arg, '"foo"';
Packit 7d6a7d
    }
Packit 7d6a7d
    else {
Packit 7d6a7d
      my $v = 'arg' . $i++;
Packit 7d6a7d
      push @arg, $v;
Packit 7d6a7d
      $stack .= "  static $n $p$v$d;\n";
Packit 7d6a7d
    }
Packit 7d6a7d
  }
Packit 7d6a7d
Packit 7d6a7d
  unless ($f->{flags}{n} || $f->{flags}{'m'}) {
Packit 7d6a7d
    $stack = "  dTHX;\n$stack";
Packit 7d6a7d
    $aTHX = @arg ? 'aTHX_ ' : 'aTHX';
Packit 7d6a7d
  }
Packit 7d6a7d
Packit 7d6a7d
  if ($stack{$f->{name}}) {
Packit 7d6a7d
    my $s = '';
Packit 7d6a7d
    for (@{$stack{$f->{name}}}) {
Packit 7d6a7d
      $s .= "  $_\n";
Packit 7d6a7d
    }
Packit 7d6a7d
    $stack = "$s$stack";
Packit 7d6a7d
  }
Packit 7d6a7d
Packit 7d6a7d
  my $args = join ', ', @arg;
Packit 7d6a7d
  my $rvt = $f->{ret} || 'void';
Packit 7d6a7d
  my $ret;
Packit 7d6a7d
  if ($void{$rvt}) {
Packit 7d6a7d
    $ret = $castvoid{$f->{name}} ? '(void) ' : '';
Packit 7d6a7d
  }
Packit 7d6a7d
  else {
Packit 7d6a7d
    $stack .= "  $rvt rval;\n";
Packit 7d6a7d
    $ret = $ignorerv{$f->{name}} ? '(void) ' : "rval = ";
Packit 7d6a7d
  }
Packit 7d6a7d
  my $aTHX_args = "$aTHX$args";
Packit 7d6a7d
Packit 7d6a7d
  if (!$f->{flags}{'m'} or $f->{flags}{'b'} or @arg > 0) {
Packit 7d6a7d
    $args = "($args)";
Packit 7d6a7d
    $aTHX_args = "($aTHX_args)";
Packit 7d6a7d
  }
Packit 7d6a7d
Packit 7d6a7d
  print OUT <
Packit 7d6a7d
/******************************************************************************
Packit 7d6a7d
*
Packit 7d6a7d
*  $f->{name}
Packit 7d6a7d
*
Packit 7d6a7d
******************************************************************************/
Packit 7d6a7d
Packit 7d6a7d
HEAD
Packit 7d6a7d
Packit 7d6a7d
  if ($todo{$f->{name}}) {
Packit 7d6a7d
    my($ver,$sub) = $todo{$f->{name}} =~ /^5\.(\d{3})(\d{3})$/ or die;
Packit 7d6a7d
    for ($ver, $sub) {
Packit 7d6a7d
      s/^0+(\d)/$1/
Packit 7d6a7d
    }
Packit 7d6a7d
    if ($ver < 6 && $sub > 0) {
Packit 7d6a7d
      $sub =~ s/0$// or die;
Packit 7d6a7d
    }
Packit 7d6a7d
    print OUT "#if PERL_VERSION > $ver || (PERL_VERSION == $ver && PERL_SUBVERSION >= $sub) /* TODO */\n";
Packit 7d6a7d
  }
Packit 7d6a7d
Packit 7d6a7d
  my $final = $varargs
Packit 7d6a7d
              ? "$Perl_$f->{name}$aTHX_args"
Packit 7d6a7d
              : "$f->{name}$args";
Packit 7d6a7d
Packit 7d6a7d
  $f->{cond} and print OUT "#if $f->{cond}\n";
Packit 7d6a7d
Packit 7d6a7d
  print OUT <
Packit 7d6a7d
void _DPPP_test_$f->{name} (void)
Packit 7d6a7d
{
Packit 7d6a7d
  dXSARGS;
Packit 7d6a7d
$stack
Packit 7d6a7d
  {
Packit 7d6a7d
#ifdef $f->{name}
Packit 7d6a7d
    $ret$f->{name}$args;
Packit 7d6a7d
#endif
Packit 7d6a7d
  }
Packit 7d6a7d
Packit 7d6a7d
  {
Packit 7d6a7d
#ifdef $f->{name}
Packit 7d6a7d
    $ret$final;
Packit 7d6a7d
#else
Packit 7d6a7d
    $ret$Perl_$f->{name}$aTHX_args;
Packit 7d6a7d
#endif
Packit 7d6a7d
  }
Packit 7d6a7d
}
Packit 7d6a7d
END
Packit 7d6a7d
Packit 7d6a7d
  $f->{cond} and print OUT "#endif\n";
Packit 7d6a7d
  $todo{$f->{name}} and print OUT "#endif\n";
Packit 7d6a7d
Packit 7d6a7d
  print OUT "\n";
Packit 7d6a7d
}
Packit 7d6a7d
Packit 7d6a7d
@ARGV and close OUT;