#! /usr/bin/env perl
# Copyright 2018-2021 The OpenSSL Project Authors. All Rights Reserved.
#
# Licensed under the Apache License 2.0 (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.
# This changes any OPENSSL_NO_DEPRECATED_x_y[_z] check to a check of
# OPENSSL_NO_DEPRECATEDIN_x_y[_z]. That's due to <openssl/macros.h>
# creating OPENSSL_NO_DEPRECATED_x_y[_z], but the ordinals files using
# DEPRECATEDIN_x_y[_z].
{ regexp => qr/#if(def|ndef) OPENSSL_NO_DEPRECATED_(\d+_\d+(?:_\d+)?)$/,
massager => sub {
return (<<"EOF");
#if$1 OPENSSL_NO_DEPRECATEDIN_$2
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: ", scalar(@preprocessor_conds), "\n"
if