#! /usr/bin/env perl
# Copyright 2018 The OpenSSL Project Authors. All Rights Reserved.
#
# Licensed under the OpenSSL license (the "License"). You may not use
# this file except in compliance with the License. You can obtain a copy
# in the file LICENSE in the source distribution or at
# https://www.openssl.org/source/license.html
package OpenSSL::ParseC;
use strict;
use warnings;
use Exporter;
use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
$VERSION = "0.9";
@ISA = qw(Exporter);
@EXPORT = qw(parse);
# Global handler data
my @preprocessor_conds; # A list of simple preprocessor conditions,
# each item being a list of macros defined
# or not defined.
# Handler helpers
sub all_conds {
return map { ( @$_ ) } @preprocessor_conds;
}
# A list of handlers that will look at a "complete" string and try to
# figure out what to make of it.
# Each handler is a hash with the following keys:
#
# regexp a regexp to compare the "complete" string with.
# checker a function that does a more complex comparison.
# Use this instead of regexp if that isn't enough.
# massager massages the "complete" string into an array with
# the following elements:
#
# [0] String that needs further processing (this
# applies to typedefs of structs), or empty.
# [1] The name of what was found.
# [2] A character that denotes what type of thing
# this is: 'F' for function, 'S' for struct,
# 'T' for typedef, 'M' for macro, 'V' for
# variable.
# [3] Return type (only for type 'F' and 'V')
# [4] Value (for type 'M') or signature (for type 'F',
# 'V', 'T' or 'S')
# [5...] The list of preprocessor conditions this is
# found in, as in checks for macro definitions
# (stored as the macro's name) or the absence
# of definition (stored as the macro's name
# prefixed with a '!'
#
# If the massager returns an empty list, it means the
# "complete" string has side effects but should otherwise
# be ignored.
# If the massager is undefined, the "complete" string
# should be ignored.
my @opensslcpphandlers = (
##################################################################
# OpenSSL CPP specials
#
# These are used to convert certain pre-precessor expressions into
# others that @cpphandlers have a better chance to understand.
{ regexp => qr/#if OPENSSL_API_COMPAT(\S+)(0x[0-9a-fA-F]{8})L$/,
massager => sub {
my $op = $1;
my $v = hex($2);
if ($op ne '<' && $op ne '>=') {
die "Error: unacceptable operator $op: $_[0]\n";
}
my ($one, $major, $minor) =
( ($v >> 28) & 0xf,
($v >> 20) & 0xff,
($v >> 12) & 0xff );
my $t = "DEPRECATEDIN_${one}_${major}_${minor}";
my $cond = $op eq '<' ? 'ifndef' : 'ifdef';
return (<<"EOF");
#$cond $t
EOF
}
}
);
my @cpphandlers = (
##################################################################
# CPP stuff
{ regexp => qr/#ifdef ?(.*)/,
massager => sub {
my %opts;
if (ref($_[$#_]) eq "HASH") {
%opts = %{$_[$#_]};
pop @_;
}
push @preprocessor_conds, [ $1 ];
print STDERR "DEBUG[",$opts{debug_type},"]: preprocessor level: ", scalar(@preprocessor_conds), "\n"
if $opts{debug};
return ();
},
},
{ regexp => qr/#ifndef ?(.*)/,
massager => sub {
my %opts;
if (ref($_[$#_]) eq "HASH") {
%opts = %{$_[$#_]};
pop @_;
}
push @preprocessor_conds, [ '!'.$1 ];
print STDERR "DEBUG[",$opts{debug_type},"]: preprocessor level: "