1e1051a39Sopenharmony_ci#! /usr/bin/env perl 2e1051a39Sopenharmony_ci# Copyright 2018-2021 The OpenSSL Project Authors. All Rights Reserved. 3e1051a39Sopenharmony_ci# 4e1051a39Sopenharmony_ci# Licensed under the Apache License 2.0 (the "License"). You may not use 5e1051a39Sopenharmony_ci# this file except in compliance with the License. You can obtain a copy 6e1051a39Sopenharmony_ci# in the file LICENSE in the source distribution or at 7e1051a39Sopenharmony_ci# https://www.openssl.org/source/license.html 8e1051a39Sopenharmony_ci 9e1051a39Sopenharmony_cipackage OpenSSL::ParseC; 10e1051a39Sopenharmony_ci 11e1051a39Sopenharmony_ciuse strict; 12e1051a39Sopenharmony_ciuse warnings; 13e1051a39Sopenharmony_ci 14e1051a39Sopenharmony_ciuse Exporter; 15e1051a39Sopenharmony_ciuse vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS); 16e1051a39Sopenharmony_ci$VERSION = "0.9"; 17e1051a39Sopenharmony_ci@ISA = qw(Exporter); 18e1051a39Sopenharmony_ci@EXPORT = qw(parse); 19e1051a39Sopenharmony_ci 20e1051a39Sopenharmony_ci# Global handler data 21e1051a39Sopenharmony_cimy @preprocessor_conds; # A list of simple preprocessor conditions, 22e1051a39Sopenharmony_ci # each item being a list of macros defined 23e1051a39Sopenharmony_ci # or not defined. 24e1051a39Sopenharmony_ci 25e1051a39Sopenharmony_ci# Handler helpers 26e1051a39Sopenharmony_cisub all_conds { 27e1051a39Sopenharmony_ci return map { ( @$_ ) } @preprocessor_conds; 28e1051a39Sopenharmony_ci} 29e1051a39Sopenharmony_ci 30e1051a39Sopenharmony_ci# A list of handlers that will look at a "complete" string and try to 31e1051a39Sopenharmony_ci# figure out what to make of it. 32e1051a39Sopenharmony_ci# Each handler is a hash with the following keys: 33e1051a39Sopenharmony_ci# 34e1051a39Sopenharmony_ci# regexp a regexp to compare the "complete" string with. 35e1051a39Sopenharmony_ci# checker a function that does a more complex comparison. 36e1051a39Sopenharmony_ci# Use this instead of regexp if that isn't enough. 37e1051a39Sopenharmony_ci# massager massages the "complete" string into an array with 38e1051a39Sopenharmony_ci# the following elements: 39e1051a39Sopenharmony_ci# 40e1051a39Sopenharmony_ci# [0] String that needs further processing (this 41e1051a39Sopenharmony_ci# applies to typedefs of structs), or empty. 42e1051a39Sopenharmony_ci# [1] The name of what was found. 43e1051a39Sopenharmony_ci# [2] A character that denotes what type of thing 44e1051a39Sopenharmony_ci# this is: 'F' for function, 'S' for struct, 45e1051a39Sopenharmony_ci# 'T' for typedef, 'M' for macro, 'V' for 46e1051a39Sopenharmony_ci# variable. 47e1051a39Sopenharmony_ci# [3] Return type (only for type 'F' and 'V') 48e1051a39Sopenharmony_ci# [4] Value (for type 'M') or signature (for type 'F', 49e1051a39Sopenharmony_ci# 'V', 'T' or 'S') 50e1051a39Sopenharmony_ci# [5...] The list of preprocessor conditions this is 51e1051a39Sopenharmony_ci# found in, as in checks for macro definitions 52e1051a39Sopenharmony_ci# (stored as the macro's name) or the absence 53e1051a39Sopenharmony_ci# of definition (stored as the macro's name 54e1051a39Sopenharmony_ci# prefixed with a '!' 55e1051a39Sopenharmony_ci# 56e1051a39Sopenharmony_ci# If the massager returns an empty list, it means the 57e1051a39Sopenharmony_ci# "complete" string has side effects but should otherwise 58e1051a39Sopenharmony_ci# be ignored. 59e1051a39Sopenharmony_ci# If the massager is undefined, the "complete" string 60e1051a39Sopenharmony_ci# should be ignored. 61e1051a39Sopenharmony_cimy @opensslcpphandlers = ( 62e1051a39Sopenharmony_ci ################################################################## 63e1051a39Sopenharmony_ci # OpenSSL CPP specials 64e1051a39Sopenharmony_ci # 65e1051a39Sopenharmony_ci # These are used to convert certain pre-precessor expressions into 66e1051a39Sopenharmony_ci # others that @cpphandlers have a better chance to understand. 67e1051a39Sopenharmony_ci 68e1051a39Sopenharmony_ci # This changes any OPENSSL_NO_DEPRECATED_x_y[_z] check to a check of 69e1051a39Sopenharmony_ci # OPENSSL_NO_DEPRECATEDIN_x_y[_z]. That's due to <openssl/macros.h> 70e1051a39Sopenharmony_ci # creating OPENSSL_NO_DEPRECATED_x_y[_z], but the ordinals files using 71e1051a39Sopenharmony_ci # DEPRECATEDIN_x_y[_z]. 72e1051a39Sopenharmony_ci { regexp => qr/#if(def|ndef) OPENSSL_NO_DEPRECATED_(\d+_\d+(?:_\d+)?)$/, 73e1051a39Sopenharmony_ci massager => sub { 74e1051a39Sopenharmony_ci return (<<"EOF"); 75e1051a39Sopenharmony_ci#if$1 OPENSSL_NO_DEPRECATEDIN_$2 76e1051a39Sopenharmony_ciEOF 77e1051a39Sopenharmony_ci } 78e1051a39Sopenharmony_ci } 79e1051a39Sopenharmony_ci); 80e1051a39Sopenharmony_cimy @cpphandlers = ( 81e1051a39Sopenharmony_ci ################################################################## 82e1051a39Sopenharmony_ci # CPP stuff 83e1051a39Sopenharmony_ci 84e1051a39Sopenharmony_ci { regexp => qr/#ifdef ?(.*)/, 85e1051a39Sopenharmony_ci massager => sub { 86e1051a39Sopenharmony_ci my %opts; 87e1051a39Sopenharmony_ci if (ref($_[$#_]) eq "HASH") { 88e1051a39Sopenharmony_ci %opts = %{$_[$#_]}; 89e1051a39Sopenharmony_ci pop @_; 90e1051a39Sopenharmony_ci } 91e1051a39Sopenharmony_ci push @preprocessor_conds, [ $1 ]; 92e1051a39Sopenharmony_ci print STDERR "DEBUG[",$opts{debug_type},"]: preprocessor level: ", scalar(@preprocessor_conds), "\n" 93e1051a39Sopenharmony_ci if $opts{debug}; 94e1051a39Sopenharmony_ci return (); 95e1051a39Sopenharmony_ci }, 96e1051a39Sopenharmony_ci }, 97e1051a39Sopenharmony_ci { regexp => qr/#ifndef ?(.*)/, 98e1051a39Sopenharmony_ci massager => sub { 99e1051a39Sopenharmony_ci my %opts; 100e1051a39Sopenharmony_ci if (ref($_[$#_]) eq "HASH") { 101e1051a39Sopenharmony_ci %opts = %{$_[$#_]}; 102e1051a39Sopenharmony_ci pop @_; 103e1051a39Sopenharmony_ci } 104e1051a39Sopenharmony_ci push @preprocessor_conds, [ '!'.$1 ]; 105e1051a39Sopenharmony_ci print STDERR "DEBUG[",$opts{debug_type},"]: preprocessor level: ", scalar(@preprocessor_conds), "\n" 106e1051a39Sopenharmony_ci if $opts{debug}; 107e1051a39Sopenharmony_ci return (); 108e1051a39Sopenharmony_ci }, 109e1051a39Sopenharmony_ci }, 110e1051a39Sopenharmony_ci { regexp => qr/#if (0|1)/, 111e1051a39Sopenharmony_ci massager => sub { 112e1051a39Sopenharmony_ci my %opts; 113e1051a39Sopenharmony_ci if (ref($_[$#_]) eq "HASH") { 114e1051a39Sopenharmony_ci %opts = %{$_[$#_]}; 115e1051a39Sopenharmony_ci pop @_; 116e1051a39Sopenharmony_ci } 117e1051a39Sopenharmony_ci if ($1 eq "1") { 118e1051a39Sopenharmony_ci push @preprocessor_conds, [ "TRUE" ]; 119e1051a39Sopenharmony_ci } else { 120e1051a39Sopenharmony_ci push @preprocessor_conds, [ "!TRUE" ]; 121e1051a39Sopenharmony_ci } 122e1051a39Sopenharmony_ci print STDERR "DEBUG[",$opts{debug_type},"]: preprocessor level: ", scalar(@preprocessor_conds), "\n" 123e1051a39Sopenharmony_ci if $opts{debug}; 124e1051a39Sopenharmony_ci return (); 125e1051a39Sopenharmony_ci }, 126e1051a39Sopenharmony_ci }, 127e1051a39Sopenharmony_ci { regexp => qr/#if ?(.*)/, 128e1051a39Sopenharmony_ci massager => sub { 129e1051a39Sopenharmony_ci my %opts; 130e1051a39Sopenharmony_ci if (ref($_[$#_]) eq "HASH") { 131e1051a39Sopenharmony_ci %opts = %{$_[$#_]}; 132e1051a39Sopenharmony_ci pop @_; 133e1051a39Sopenharmony_ci } 134e1051a39Sopenharmony_ci my @results = (); 135e1051a39Sopenharmony_ci my $conds = $1; 136e1051a39Sopenharmony_ci if ($conds =~ m|^defined<<<\(([^\)]*)\)>>>(.*)$|) { 137e1051a39Sopenharmony_ci push @results, $1; # Handle the simple case 138e1051a39Sopenharmony_ci my $rest = $2; 139e1051a39Sopenharmony_ci my $re = qr/^(?:\|\|defined<<<\([^\)]*\)>>>)*$/; 140e1051a39Sopenharmony_ci print STDERR "DEBUG[",$opts{debug_type},"]: Matching '$rest' with '$re'\n" 141e1051a39Sopenharmony_ci if $opts{debug}; 142e1051a39Sopenharmony_ci if ($rest =~ m/$re/) { 143e1051a39Sopenharmony_ci my @rest = split /\|\|/, $rest; 144e1051a39Sopenharmony_ci shift @rest; 145e1051a39Sopenharmony_ci foreach (@rest) { 146e1051a39Sopenharmony_ci m|^defined<<<\(([^\)]*)\)>>>$|; 147e1051a39Sopenharmony_ci die "Something wrong...$opts{PLACE}" if $1 eq ""; 148e1051a39Sopenharmony_ci push @results, $1; 149e1051a39Sopenharmony_ci } 150e1051a39Sopenharmony_ci } else { 151e1051a39Sopenharmony_ci $conds =~ s/<<<|>>>//g; 152e1051a39Sopenharmony_ci warn "Warning: complicated #if expression(1): $conds$opts{PLACE}" 153e1051a39Sopenharmony_ci if $opts{warnings}; 154e1051a39Sopenharmony_ci } 155e1051a39Sopenharmony_ci } elsif ($conds =~ m|^!defined<<<\(([^\)]*)\)>>>(.*)$|) { 156e1051a39Sopenharmony_ci push @results, '!'.$1; # Handle the simple case 157e1051a39Sopenharmony_ci my $rest = $2; 158e1051a39Sopenharmony_ci my $re = qr/^(?:\&\&!defined<<<\([^\)]*\)>>>)*$/; 159e1051a39Sopenharmony_ci print STDERR "DEBUG[",$opts{debug_type},"]: Matching '$rest' with '$re'\n" 160e1051a39Sopenharmony_ci if $opts{debug}; 161e1051a39Sopenharmony_ci if ($rest =~ m/$re/) { 162e1051a39Sopenharmony_ci my @rest = split /\&\&/, $rest; 163e1051a39Sopenharmony_ci shift @rest; 164e1051a39Sopenharmony_ci foreach (@rest) { 165e1051a39Sopenharmony_ci m|^!defined<<<\(([^\)]*)\)>>>$|; 166e1051a39Sopenharmony_ci die "Something wrong...$opts{PLACE}" if $1 eq ""; 167e1051a39Sopenharmony_ci push @results, '!'.$1; 168e1051a39Sopenharmony_ci } 169e1051a39Sopenharmony_ci } else { 170e1051a39Sopenharmony_ci $conds =~ s/<<<|>>>//g; 171e1051a39Sopenharmony_ci warn "Warning: complicated #if expression(2): $conds$opts{PLACE}" 172e1051a39Sopenharmony_ci if $opts{warnings}; 173e1051a39Sopenharmony_ci } 174e1051a39Sopenharmony_ci } else { 175e1051a39Sopenharmony_ci $conds =~ s/<<<|>>>//g; 176e1051a39Sopenharmony_ci warn "Warning: complicated #if expression(3): $conds$opts{PLACE}" 177e1051a39Sopenharmony_ci if $opts{warnings}; 178e1051a39Sopenharmony_ci } 179e1051a39Sopenharmony_ci print STDERR "DEBUG[",$opts{debug_type},"]: Added preprocessor conds: '", join("', '", @results), "'\n" 180e1051a39Sopenharmony_ci if $opts{debug}; 181e1051a39Sopenharmony_ci push @preprocessor_conds, [ @results ]; 182e1051a39Sopenharmony_ci print STDERR "DEBUG[",$opts{debug_type},"]: preprocessor level: ", scalar(@preprocessor_conds), "\n" 183e1051a39Sopenharmony_ci if $opts{debug}; 184e1051a39Sopenharmony_ci return (); 185e1051a39Sopenharmony_ci }, 186e1051a39Sopenharmony_ci }, 187e1051a39Sopenharmony_ci { regexp => qr/#elif (.*)/, 188e1051a39Sopenharmony_ci massager => sub { 189e1051a39Sopenharmony_ci my %opts; 190e1051a39Sopenharmony_ci if (ref($_[$#_]) eq "HASH") { 191e1051a39Sopenharmony_ci %opts = %{$_[$#_]}; 192e1051a39Sopenharmony_ci pop @_; 193e1051a39Sopenharmony_ci } 194e1051a39Sopenharmony_ci die "An #elif without corresponding condition$opts{PLACE}" 195e1051a39Sopenharmony_ci if !@preprocessor_conds; 196e1051a39Sopenharmony_ci pop @preprocessor_conds; 197e1051a39Sopenharmony_ci print STDERR "DEBUG[",$opts{debug_type},"]: preprocessor level: ", scalar(@preprocessor_conds), "\n" 198e1051a39Sopenharmony_ci if $opts{debug}; 199e1051a39Sopenharmony_ci return (<<"EOF"); 200e1051a39Sopenharmony_ci#if $1 201e1051a39Sopenharmony_ciEOF 202e1051a39Sopenharmony_ci }, 203e1051a39Sopenharmony_ci }, 204e1051a39Sopenharmony_ci { regexp => qr/#else/, 205e1051a39Sopenharmony_ci massager => sub { 206e1051a39Sopenharmony_ci my %opts; 207e1051a39Sopenharmony_ci if (ref($_[$#_]) eq "HASH") { 208e1051a39Sopenharmony_ci %opts = %{$_[$#_]}; 209e1051a39Sopenharmony_ci pop @_; 210e1051a39Sopenharmony_ci } 211e1051a39Sopenharmony_ci die "An #else without corresponding condition$opts{PLACE}" 212e1051a39Sopenharmony_ci if !@preprocessor_conds; 213e1051a39Sopenharmony_ci # Invert all conditions on the last level 214e1051a39Sopenharmony_ci my $stuff = pop @preprocessor_conds; 215e1051a39Sopenharmony_ci push @preprocessor_conds, [ 216e1051a39Sopenharmony_ci map { m|^!(.*)$| ? $1 : '!'.$_ } @$stuff 217e1051a39Sopenharmony_ci ]; 218e1051a39Sopenharmony_ci print STDERR "DEBUG[",$opts{debug_type},"]: preprocessor level: ", scalar(@preprocessor_conds), "\n" 219e1051a39Sopenharmony_ci if $opts{debug}; 220e1051a39Sopenharmony_ci return (); 221e1051a39Sopenharmony_ci }, 222e1051a39Sopenharmony_ci }, 223e1051a39Sopenharmony_ci { regexp => qr/#endif ?/, 224e1051a39Sopenharmony_ci massager => sub { 225e1051a39Sopenharmony_ci my %opts; 226e1051a39Sopenharmony_ci if (ref($_[$#_]) eq "HASH") { 227e1051a39Sopenharmony_ci %opts = %{$_[$#_]}; 228e1051a39Sopenharmony_ci pop @_; 229e1051a39Sopenharmony_ci } 230e1051a39Sopenharmony_ci die "An #endif without corresponding condition$opts{PLACE}" 231e1051a39Sopenharmony_ci if !@preprocessor_conds; 232e1051a39Sopenharmony_ci pop @preprocessor_conds; 233e1051a39Sopenharmony_ci print STDERR "DEBUG[",$opts{debug_type},"]: preprocessor level: ", scalar(@preprocessor_conds), "\n" 234e1051a39Sopenharmony_ci if $opts{debug}; 235e1051a39Sopenharmony_ci return (); 236e1051a39Sopenharmony_ci }, 237e1051a39Sopenharmony_ci }, 238e1051a39Sopenharmony_ci { regexp => qr/#define ([[:alpha:]_]\w*)(<<<\(.*?\)>>>)?( (.*))?/, 239e1051a39Sopenharmony_ci massager => sub { 240e1051a39Sopenharmony_ci my $name = $1; 241e1051a39Sopenharmony_ci my $params = $2; 242e1051a39Sopenharmony_ci my $spaceval = $3||""; 243e1051a39Sopenharmony_ci my $val = $4||""; 244e1051a39Sopenharmony_ci return ("", 245e1051a39Sopenharmony_ci $1, 'M', "", $params ? "$name$params$spaceval" : $val, 246e1051a39Sopenharmony_ci all_conds()); } 247e1051a39Sopenharmony_ci }, 248e1051a39Sopenharmony_ci { regexp => qr/#.*/, 249e1051a39Sopenharmony_ci massager => sub { return (); } 250e1051a39Sopenharmony_ci }, 251e1051a39Sopenharmony_ci ); 252e1051a39Sopenharmony_ci 253e1051a39Sopenharmony_cimy @opensslchandlers = ( 254e1051a39Sopenharmony_ci ################################################################## 255e1051a39Sopenharmony_ci # OpenSSL C specials 256e1051a39Sopenharmony_ci # 257e1051a39Sopenharmony_ci # They are really preprocessor stuff, but they look like C stuff 258e1051a39Sopenharmony_ci # to this parser. All of these do replacements, anything else is 259e1051a39Sopenharmony_ci # an error. 260e1051a39Sopenharmony_ci 261e1051a39Sopenharmony_ci ##### 262e1051a39Sopenharmony_ci # Deprecated stuff, by OpenSSL release. 263e1051a39Sopenharmony_ci 264e1051a39Sopenharmony_ci # OSSL_DEPRECATEDIN_x_y[_z] is simply ignored. Such declarations are 265e1051a39Sopenharmony_ci # supposed to be guarded with an '#ifdef OPENSSL_NO_DEPRECATED_x_y[_z]' 266e1051a39Sopenharmony_ci { regexp => qr/OSSL_DEPRECATEDIN_\d+_\d+(?:_\d+)?\s+(.*)/, 267e1051a39Sopenharmony_ci massager => sub { return $1; }, 268e1051a39Sopenharmony_ci }, 269e1051a39Sopenharmony_ci { regexp => qr/(.*?)\s+OSSL_DEPRECATEDIN_\d+_\d+(?:_\d+)?\s+(.*)/, 270e1051a39Sopenharmony_ci massager => sub { return "$1 $2"; }, 271e1051a39Sopenharmony_ci }, 272e1051a39Sopenharmony_ci 273e1051a39Sopenharmony_ci ##### 274e1051a39Sopenharmony_ci # Core stuff 275e1051a39Sopenharmony_ci 276e1051a39Sopenharmony_ci # OSSL_CORE_MAKE_FUNC is a macro to create the necessary data and inline 277e1051a39Sopenharmony_ci # function the libcrypto<->provider interface 278e1051a39Sopenharmony_ci { regexp => qr/OSSL_CORE_MAKE_FUNC<<<\((.*?),(.*?),(.*?)\)>>>/, 279e1051a39Sopenharmony_ci massager => sub { 280e1051a39Sopenharmony_ci return (<<"EOF"); 281e1051a39Sopenharmony_citypedef $1 OSSL_FUNC_$2_fn$3; 282e1051a39Sopenharmony_cistatic ossl_inline OSSL_FUNC_$2_fn *OSSL_FUNC_$2(const OSSL_DISPATCH *opf); 283e1051a39Sopenharmony_ciEOF 284e1051a39Sopenharmony_ci }, 285e1051a39Sopenharmony_ci }, 286e1051a39Sopenharmony_ci 287e1051a39Sopenharmony_ci ##### 288e1051a39Sopenharmony_ci # LHASH stuff 289e1051a39Sopenharmony_ci 290e1051a39Sopenharmony_ci # LHASH_OF(foo) is used as a type, but the chandlers won't take it 291e1051a39Sopenharmony_ci # gracefully, so we expand it here. 292e1051a39Sopenharmony_ci { regexp => qr/(.*)\bLHASH_OF<<<\((.*?)\)>>>(.*)/, 293e1051a39Sopenharmony_ci massager => sub { return ("$1struct lhash_st_$2$3"); } 294e1051a39Sopenharmony_ci }, 295e1051a39Sopenharmony_ci { regexp => qr/DEFINE_LHASH_OF(?:_INTERNAL)?<<<\((.*)\)>>>/, 296e1051a39Sopenharmony_ci massager => sub { 297e1051a39Sopenharmony_ci return (<<"EOF"); 298e1051a39Sopenharmony_cistatic ossl_inline LHASH_OF($1) * lh_$1_new(unsigned long (*hfn)(const $1 *), 299e1051a39Sopenharmony_ci int (*cfn)(const $1 *, const $1 *)); 300e1051a39Sopenharmony_cistatic ossl_inline void lh_$1_free(LHASH_OF($1) *lh); 301e1051a39Sopenharmony_cistatic ossl_inline $1 *lh_$1_insert(LHASH_OF($1) *lh, $1 *d); 302e1051a39Sopenharmony_cistatic ossl_inline $1 *lh_$1_delete(LHASH_OF($1) *lh, const $1 *d); 303e1051a39Sopenharmony_cistatic ossl_inline $1 *lh_$1_retrieve(LHASH_OF($1) *lh, const $1 *d); 304e1051a39Sopenharmony_cistatic ossl_inline int lh_$1_error(LHASH_OF($1) *lh); 305e1051a39Sopenharmony_cistatic ossl_inline unsigned long lh_$1_num_items(LHASH_OF($1) *lh); 306e1051a39Sopenharmony_cistatic ossl_inline void lh_$1_node_stats_bio(const LHASH_OF($1) *lh, BIO *out); 307e1051a39Sopenharmony_cistatic ossl_inline void lh_$1_node_usage_stats_bio(const LHASH_OF($1) *lh, 308e1051a39Sopenharmony_ci BIO *out); 309e1051a39Sopenharmony_cistatic ossl_inline void lh_$1_stats_bio(const LHASH_OF($1) *lh, BIO *out); 310e1051a39Sopenharmony_cistatic ossl_inline unsigned long lh_$1_get_down_load(LHASH_OF($1) *lh); 311e1051a39Sopenharmony_cistatic ossl_inline void lh_$1_set_down_load(LHASH_OF($1) *lh, unsigned long dl); 312e1051a39Sopenharmony_cistatic ossl_inline void lh_$1_doall(LHASH_OF($1) *lh, void (*doall)($1 *)); 313e1051a39Sopenharmony_ciLHASH_OF($1) 314e1051a39Sopenharmony_ciEOF 315e1051a39Sopenharmony_ci } 316e1051a39Sopenharmony_ci }, 317e1051a39Sopenharmony_ci 318e1051a39Sopenharmony_ci ##### 319e1051a39Sopenharmony_ci # STACK stuff 320e1051a39Sopenharmony_ci 321e1051a39Sopenharmony_ci # STACK_OF(foo) is used as a type, but the chandlers won't take it 322e1051a39Sopenharmony_ci # gracefully, so we expand it here. 323e1051a39Sopenharmony_ci { regexp => qr/(.*)\bSTACK_OF<<<\((.*?)\)>>>(.*)/, 324e1051a39Sopenharmony_ci massager => sub { return ("$1struct stack_st_$2$3"); } 325e1051a39Sopenharmony_ci }, 326e1051a39Sopenharmony_ci# { regexp => qr/(.*)\bSTACK_OF\((.*?)\)(.*)/, 327e1051a39Sopenharmony_ci# massager => sub { 328e1051a39Sopenharmony_ci# my $before = $1; 329e1051a39Sopenharmony_ci# my $stack_of = "struct stack_st_$2"; 330e1051a39Sopenharmony_ci# my $after = $3; 331e1051a39Sopenharmony_ci# if ($after =~ m|^\w|) { $after = " ".$after; } 332e1051a39Sopenharmony_ci# return ("$before$stack_of$after"); 333e1051a39Sopenharmony_ci# } 334e1051a39Sopenharmony_ci# }, 335e1051a39Sopenharmony_ci { regexp => qr/SKM_DEFINE_STACK_OF<<<\((.*),\s*(.*),\s*(.*)\)>>>/, 336e1051a39Sopenharmony_ci massager => sub { 337e1051a39Sopenharmony_ci return (<<"EOF"); 338e1051a39Sopenharmony_ciSTACK_OF($1); 339e1051a39Sopenharmony_citypedef int (*sk_$1_compfunc)(const $3 * const *a, const $3 *const *b); 340e1051a39Sopenharmony_citypedef void (*sk_$1_freefunc)($3 *a); 341e1051a39Sopenharmony_citypedef $3 * (*sk_$1_copyfunc)(const $3 *a); 342e1051a39Sopenharmony_cistatic ossl_inline int sk_$1_num(const STACK_OF($1) *sk); 343e1051a39Sopenharmony_cistatic ossl_inline $2 *sk_$1_value(const STACK_OF($1) *sk, int idx); 344e1051a39Sopenharmony_cistatic ossl_inline STACK_OF($1) *sk_$1_new(sk_$1_compfunc compare); 345e1051a39Sopenharmony_cistatic ossl_inline STACK_OF($1) *sk_$1_new_null(void); 346e1051a39Sopenharmony_cistatic ossl_inline STACK_OF($1) *sk_$1_new_reserve(sk_$1_compfunc compare, 347e1051a39Sopenharmony_ci int n); 348e1051a39Sopenharmony_cistatic ossl_inline int sk_$1_reserve(STACK_OF($1) *sk, int n); 349e1051a39Sopenharmony_cistatic ossl_inline void sk_$1_free(STACK_OF($1) *sk); 350e1051a39Sopenharmony_cistatic ossl_inline void sk_$1_zero(STACK_OF($1) *sk); 351e1051a39Sopenharmony_cistatic ossl_inline $2 *sk_$1_delete(STACK_OF($1) *sk, int i); 352e1051a39Sopenharmony_cistatic ossl_inline $2 *sk_$1_delete_ptr(STACK_OF($1) *sk, $2 *ptr); 353e1051a39Sopenharmony_cistatic ossl_inline int sk_$1_push(STACK_OF($1) *sk, $2 *ptr); 354e1051a39Sopenharmony_cistatic ossl_inline int sk_$1_unshift(STACK_OF($1) *sk, $2 *ptr); 355e1051a39Sopenharmony_cistatic ossl_inline $2 *sk_$1_pop(STACK_OF($1) *sk); 356e1051a39Sopenharmony_cistatic ossl_inline $2 *sk_$1_shift(STACK_OF($1) *sk); 357e1051a39Sopenharmony_cistatic ossl_inline void sk_$1_pop_free(STACK_OF($1) *sk, 358e1051a39Sopenharmony_ci sk_$1_freefunc freefunc); 359e1051a39Sopenharmony_cistatic ossl_inline int sk_$1_insert(STACK_OF($1) *sk, $2 *ptr, int idx); 360e1051a39Sopenharmony_cistatic ossl_inline $2 *sk_$1_set(STACK_OF($1) *sk, int idx, $2 *ptr); 361e1051a39Sopenharmony_cistatic ossl_inline int sk_$1_find(STACK_OF($1) *sk, $2 *ptr); 362e1051a39Sopenharmony_cistatic ossl_inline int sk_$1_find_ex(STACK_OF($1) *sk, $2 *ptr); 363e1051a39Sopenharmony_cistatic ossl_inline void sk_$1_sort(STACK_OF($1) *sk); 364e1051a39Sopenharmony_cistatic ossl_inline int sk_$1_is_sorted(const STACK_OF($1) *sk); 365e1051a39Sopenharmony_cistatic ossl_inline STACK_OF($1) * sk_$1_dup(const STACK_OF($1) *sk); 366e1051a39Sopenharmony_cistatic ossl_inline STACK_OF($1) *sk_$1_deep_copy(const STACK_OF($1) *sk, 367e1051a39Sopenharmony_ci sk_$1_copyfunc copyfunc, 368e1051a39Sopenharmony_ci sk_$1_freefunc freefunc); 369e1051a39Sopenharmony_cistatic ossl_inline sk_$1_compfunc sk_$1_set_cmp_func(STACK_OF($1) *sk, 370e1051a39Sopenharmony_ci sk_$1_compfunc compare); 371e1051a39Sopenharmony_ciEOF 372e1051a39Sopenharmony_ci } 373e1051a39Sopenharmony_ci }, 374e1051a39Sopenharmony_ci { regexp => qr/SKM_DEFINE_STACK_OF_INTERNAL<<<\((.*),\s*(.*),\s*(.*)\)>>>/, 375e1051a39Sopenharmony_ci massager => sub { 376e1051a39Sopenharmony_ci return (<<"EOF"); 377e1051a39Sopenharmony_ciSTACK_OF($1); 378e1051a39Sopenharmony_citypedef int (*sk_$1_compfunc)(const $3 * const *a, const $3 *const *b); 379e1051a39Sopenharmony_citypedef void (*sk_$1_freefunc)($3 *a); 380e1051a39Sopenharmony_citypedef $3 * (*sk_$1_copyfunc)(const $3 *a); 381e1051a39Sopenharmony_cistatic ossl_unused ossl_inline $2 *ossl_check_$1_type($2 *ptr); 382e1051a39Sopenharmony_cistatic ossl_unused ossl_inline const OPENSSL_STACK *ossl_check_const_$1_sk_type(const STACK_OF($1) *sk); 383e1051a39Sopenharmony_cistatic ossl_unused ossl_inline OPENSSL_sk_compfunc ossl_check_$1_compfunc_type(sk_$1_compfunc cmp); 384e1051a39Sopenharmony_cistatic ossl_unused ossl_inline OPENSSL_sk_copyfunc ossl_check_$1_copyfunc_type(sk_$1_copyfunc cpy); 385e1051a39Sopenharmony_cistatic ossl_unused ossl_inline OPENSSL_sk_freefunc ossl_check_$1_freefunc_type(sk_$1_freefunc fr); 386e1051a39Sopenharmony_ciEOF 387e1051a39Sopenharmony_ci } 388e1051a39Sopenharmony_ci }, 389e1051a39Sopenharmony_ci { regexp => qr/DEFINE_SPECIAL_STACK_OF<<<\((.*),\s*(.*)\)>>>/, 390e1051a39Sopenharmony_ci massager => sub { return ("SKM_DEFINE_STACK_OF($1,$2,$2)"); }, 391e1051a39Sopenharmony_ci }, 392e1051a39Sopenharmony_ci { regexp => qr/DEFINE_STACK_OF<<<\((.*)\)>>>/, 393e1051a39Sopenharmony_ci massager => sub { return ("SKM_DEFINE_STACK_OF($1,$1,$1)"); }, 394e1051a39Sopenharmony_ci }, 395e1051a39Sopenharmony_ci { regexp => qr/DEFINE_SPECIAL_STACK_OF_CONST<<<\((.*),\s*(.*)\)>>>/, 396e1051a39Sopenharmony_ci massager => sub { return ("SKM_DEFINE_STACK_OF($1,const $2,$2)"); }, 397e1051a39Sopenharmony_ci }, 398e1051a39Sopenharmony_ci { regexp => qr/DEFINE_STACK_OF_CONST<<<\((.*)\)>>>/, 399e1051a39Sopenharmony_ci massager => sub { return ("SKM_DEFINE_STACK_OF($1,const $1,$1)"); }, 400e1051a39Sopenharmony_ci }, 401e1051a39Sopenharmony_ci 402e1051a39Sopenharmony_ci ##### 403e1051a39Sopenharmony_ci # ASN1 stuff 404e1051a39Sopenharmony_ci { regexp => qr/DECLARE_ASN1_ITEM<<<\((.*)\)>>>/, 405e1051a39Sopenharmony_ci massager => sub { 406e1051a39Sopenharmony_ci return (<<"EOF"); 407e1051a39Sopenharmony_ciconst ASN1_ITEM *$1_it(void); 408e1051a39Sopenharmony_ciEOF 409e1051a39Sopenharmony_ci }, 410e1051a39Sopenharmony_ci }, 411e1051a39Sopenharmony_ci { regexp => qr/DECLARE_ASN1_ENCODE_FUNCTIONS_only<<<\((.*),\s*(.*)\)>>>/, 412e1051a39Sopenharmony_ci massager => sub { 413e1051a39Sopenharmony_ci return (<<"EOF"); 414e1051a39Sopenharmony_ciint d2i_$2(void); 415e1051a39Sopenharmony_ciint i2d_$2(void); 416e1051a39Sopenharmony_ciEOF 417e1051a39Sopenharmony_ci }, 418e1051a39Sopenharmony_ci }, 419e1051a39Sopenharmony_ci { regexp => qr/DECLARE_ASN1_ENCODE_FUNCTIONS<<<\((.*),\s*(.*),\s*(.*)\)>>>/, 420e1051a39Sopenharmony_ci massager => sub { 421e1051a39Sopenharmony_ci return (<<"EOF"); 422e1051a39Sopenharmony_ciint d2i_$3(void); 423e1051a39Sopenharmony_ciint i2d_$3(void); 424e1051a39Sopenharmony_ciDECLARE_ASN1_ITEM($2) 425e1051a39Sopenharmony_ciEOF 426e1051a39Sopenharmony_ci }, 427e1051a39Sopenharmony_ci }, 428e1051a39Sopenharmony_ci { regexp => qr/DECLARE_ASN1_ENCODE_FUNCTIONS_name<<<\((.*),\s*(.*)\)>>>/, 429e1051a39Sopenharmony_ci massager => sub { 430e1051a39Sopenharmony_ci return (<<"EOF"); 431e1051a39Sopenharmony_ciint d2i_$2(void); 432e1051a39Sopenharmony_ciint i2d_$2(void); 433e1051a39Sopenharmony_ciDECLARE_ASN1_ITEM($2) 434e1051a39Sopenharmony_ciEOF 435e1051a39Sopenharmony_ci }, 436e1051a39Sopenharmony_ci }, 437e1051a39Sopenharmony_ci { regexp => qr/DECLARE_ASN1_ALLOC_FUNCTIONS_name<<<\((.*),\s*(.*)\)>>>/, 438e1051a39Sopenharmony_ci massager => sub { 439e1051a39Sopenharmony_ci return (<<"EOF"); 440e1051a39Sopenharmony_ciint $2_free(void); 441e1051a39Sopenharmony_ciint $2_new(void); 442e1051a39Sopenharmony_ciEOF 443e1051a39Sopenharmony_ci }, 444e1051a39Sopenharmony_ci }, 445e1051a39Sopenharmony_ci { regexp => qr/DECLARE_ASN1_ALLOC_FUNCTIONS<<<\((.*)\)>>>/, 446e1051a39Sopenharmony_ci massager => sub { 447e1051a39Sopenharmony_ci return (<<"EOF"); 448e1051a39Sopenharmony_ciint $1_free(void); 449e1051a39Sopenharmony_ciint $1_new(void); 450e1051a39Sopenharmony_ciEOF 451e1051a39Sopenharmony_ci }, 452e1051a39Sopenharmony_ci }, 453e1051a39Sopenharmony_ci { regexp => qr/DECLARE_ASN1_FUNCTIONS_name<<<\((.*),\s*(.*)\)>>>/, 454e1051a39Sopenharmony_ci massager => sub { 455e1051a39Sopenharmony_ci return (<<"EOF"); 456e1051a39Sopenharmony_ciint d2i_$2(void); 457e1051a39Sopenharmony_ciint i2d_$2(void); 458e1051a39Sopenharmony_ciint $2_free(void); 459e1051a39Sopenharmony_ciint $2_new(void); 460e1051a39Sopenharmony_ciDECLARE_ASN1_ITEM($2) 461e1051a39Sopenharmony_ciEOF 462e1051a39Sopenharmony_ci }, 463e1051a39Sopenharmony_ci }, 464e1051a39Sopenharmony_ci { regexp => qr/DECLARE_ASN1_FUNCTIONS<<<\((.*)\)>>>/, 465e1051a39Sopenharmony_ci massager => sub { return (<<"EOF"); 466e1051a39Sopenharmony_ciint d2i_$1(void); 467e1051a39Sopenharmony_ciint i2d_$1(void); 468e1051a39Sopenharmony_ciint $1_free(void); 469e1051a39Sopenharmony_ciint $1_new(void); 470e1051a39Sopenharmony_ciDECLARE_ASN1_ITEM($1) 471e1051a39Sopenharmony_ciEOF 472e1051a39Sopenharmony_ci } 473e1051a39Sopenharmony_ci }, 474e1051a39Sopenharmony_ci { regexp => qr/DECLARE_ASN1_NDEF_FUNCTION<<<\((.*)\)>>>/, 475e1051a39Sopenharmony_ci massager => sub { 476e1051a39Sopenharmony_ci return (<<"EOF"); 477e1051a39Sopenharmony_ciint i2d_$1_NDEF(void); 478e1051a39Sopenharmony_ciEOF 479e1051a39Sopenharmony_ci } 480e1051a39Sopenharmony_ci }, 481e1051a39Sopenharmony_ci { regexp => qr/DECLARE_ASN1_PRINT_FUNCTION<<<\((.*)\)>>>/, 482e1051a39Sopenharmony_ci massager => sub { 483e1051a39Sopenharmony_ci return (<<"EOF"); 484e1051a39Sopenharmony_ciint $1_print_ctx(void); 485e1051a39Sopenharmony_ciEOF 486e1051a39Sopenharmony_ci } 487e1051a39Sopenharmony_ci }, 488e1051a39Sopenharmony_ci { regexp => qr/DECLARE_ASN1_PRINT_FUNCTION_name<<<\((.*),\s*(.*)\)>>>/, 489e1051a39Sopenharmony_ci massager => sub { 490e1051a39Sopenharmony_ci return (<<"EOF"); 491e1051a39Sopenharmony_ciint $2_print_ctx(void); 492e1051a39Sopenharmony_ciEOF 493e1051a39Sopenharmony_ci } 494e1051a39Sopenharmony_ci }, 495e1051a39Sopenharmony_ci { regexp => qr/DECLARE_ASN1_SET_OF<<<\((.*)\)>>>/, 496e1051a39Sopenharmony_ci massager => sub { return (); } 497e1051a39Sopenharmony_ci }, 498e1051a39Sopenharmony_ci { regexp => qr/DECLARE_ASN1_DUP_FUNCTION<<<\((.*)\)>>>/, 499e1051a39Sopenharmony_ci massager => sub { 500e1051a39Sopenharmony_ci return (<<"EOF"); 501e1051a39Sopenharmony_ciint $1_dup(void); 502e1051a39Sopenharmony_ciEOF 503e1051a39Sopenharmony_ci } 504e1051a39Sopenharmony_ci }, 505e1051a39Sopenharmony_ci { regexp => qr/DECLARE_ASN1_DUP_FUNCTION_name<<<\((.*),\s*(.*)\)>>>/, 506e1051a39Sopenharmony_ci massager => sub { 507e1051a39Sopenharmony_ci return (<<"EOF"); 508e1051a39Sopenharmony_ciint $2_dup(void); 509e1051a39Sopenharmony_ciEOF 510e1051a39Sopenharmony_ci } 511e1051a39Sopenharmony_ci }, 512e1051a39Sopenharmony_ci # Universal translator of attributed PEM declarators 513e1051a39Sopenharmony_ci { regexp => qr/ 514e1051a39Sopenharmony_ci DECLARE_ASN1 515e1051a39Sopenharmony_ci (_ENCODE_FUNCTIONS_only|_ENCODE_FUNCTIONS|_ENCODE_FUNCTIONS_name 516e1051a39Sopenharmony_ci |_ALLOC_FUNCTIONS_name|_ALLOC_FUNCTIONS|_FUNCTIONS_name|_FUNCTIONS 517e1051a39Sopenharmony_ci |_NDEF_FUNCTION|_PRINT_FUNCTION|_PRINT_FUNCTION_name 518e1051a39Sopenharmony_ci |_DUP_FUNCTION|_DUP_FUNCTION_name) 519e1051a39Sopenharmony_ci _attr 520e1051a39Sopenharmony_ci <<<\(\s*OSSL_DEPRECATEDIN_(.*?)\s*,(.*?)\)>>> 521e1051a39Sopenharmony_ci /x, 522e1051a39Sopenharmony_ci massager => sub { return (<<"EOF"); 523e1051a39Sopenharmony_ciDECLARE_ASN1$1($3) 524e1051a39Sopenharmony_ciEOF 525e1051a39Sopenharmony_ci }, 526e1051a39Sopenharmony_ci }, 527e1051a39Sopenharmony_ci { regexp => qr/DECLARE_PKCS12_SET_OF<<<\((.*)\)>>>/, 528e1051a39Sopenharmony_ci massager => sub { return (); } 529e1051a39Sopenharmony_ci }, 530e1051a39Sopenharmony_ci 531e1051a39Sopenharmony_ci ##### 532e1051a39Sopenharmony_ci # PEM stuff 533e1051a39Sopenharmony_ci { regexp => qr/DECLARE_PEM(?|_rw|_rw_cb|_rw_const)<<<\((.*?),.*\)>>>/, 534e1051a39Sopenharmony_ci massager => sub { return (<<"EOF"); 535e1051a39Sopenharmony_ci#ifndef OPENSSL_NO_STDIO 536e1051a39Sopenharmony_ciint PEM_read_$1(void); 537e1051a39Sopenharmony_ciint PEM_write_$1(void); 538e1051a39Sopenharmony_ci#endif 539e1051a39Sopenharmony_ciint PEM_read_bio_$1(void); 540e1051a39Sopenharmony_ciint PEM_write_bio_$1(void); 541e1051a39Sopenharmony_ciEOF 542e1051a39Sopenharmony_ci }, 543e1051a39Sopenharmony_ci }, 544e1051a39Sopenharmony_ci { regexp => qr/DECLARE_PEM(?|_rw|_rw_cb|_rw_const)_ex<<<\((.*?),.*\)>>>/, 545e1051a39Sopenharmony_ci massager => sub { return (<<"EOF"); 546e1051a39Sopenharmony_ci#ifndef OPENSSL_NO_STDIO 547e1051a39Sopenharmony_ciint PEM_read_$1(void); 548e1051a39Sopenharmony_ciint PEM_write_$1(void); 549e1051a39Sopenharmony_ciint PEM_read_$1_ex(void); 550e1051a39Sopenharmony_ciint PEM_write_$1_ex(void); 551e1051a39Sopenharmony_ci#endif 552e1051a39Sopenharmony_ciint PEM_read_bio_$1(void); 553e1051a39Sopenharmony_ciint PEM_write_bio_$1(void); 554e1051a39Sopenharmony_ciint PEM_read_bio_$1_ex(void); 555e1051a39Sopenharmony_ciint PEM_write_bio_$1_ex(void); 556e1051a39Sopenharmony_ciEOF 557e1051a39Sopenharmony_ci }, 558e1051a39Sopenharmony_ci }, 559e1051a39Sopenharmony_ci { regexp => qr/DECLARE_PEM(?|_write|_write_cb|_write_const)<<<\((.*?),.*\)>>>/, 560e1051a39Sopenharmony_ci massager => sub { return (<<"EOF"); 561e1051a39Sopenharmony_ci#ifndef OPENSSL_NO_STDIO 562e1051a39Sopenharmony_ciint PEM_write_$1(void); 563e1051a39Sopenharmony_ci#endif 564e1051a39Sopenharmony_ciint PEM_write_bio_$1(void); 565e1051a39Sopenharmony_ciEOF 566e1051a39Sopenharmony_ci }, 567e1051a39Sopenharmony_ci }, 568e1051a39Sopenharmony_ci { regexp => qr/DECLARE_PEM(?|_write|_write_cb|_write_const)_ex<<<\((.*?),.*\)>>>/, 569e1051a39Sopenharmony_ci massager => sub { return (<<"EOF"); 570e1051a39Sopenharmony_ci#ifndef OPENSSL_NO_STDIO 571e1051a39Sopenharmony_ciint PEM_write_$1(void); 572e1051a39Sopenharmony_ciint PEM_write_$1_ex(void); 573e1051a39Sopenharmony_ci#endif 574e1051a39Sopenharmony_ciint PEM_write_bio_$1(void); 575e1051a39Sopenharmony_ciint PEM_write_bio_$1_ex(void); 576e1051a39Sopenharmony_ciEOF 577e1051a39Sopenharmony_ci }, 578e1051a39Sopenharmony_ci }, 579e1051a39Sopenharmony_ci { regexp => qr/DECLARE_PEM(?|_read|_read_cb)<<<\((.*?),.*\)>>>/, 580e1051a39Sopenharmony_ci massager => sub { return (<<"EOF"); 581e1051a39Sopenharmony_ci#ifndef OPENSSL_NO_STDIO 582e1051a39Sopenharmony_ciint PEM_read_$1(void); 583e1051a39Sopenharmony_ci#endif 584e1051a39Sopenharmony_ciint PEM_read_bio_$1(void); 585e1051a39Sopenharmony_ciEOF 586e1051a39Sopenharmony_ci }, 587e1051a39Sopenharmony_ci }, 588e1051a39Sopenharmony_ci { regexp => qr/DECLARE_PEM(?|_read|_read_cb)_ex<<<\((.*?),.*\)>>>/, 589e1051a39Sopenharmony_ci massager => sub { return (<<"EOF"); 590e1051a39Sopenharmony_ci#ifndef OPENSSL_NO_STDIO 591e1051a39Sopenharmony_ciint PEM_read_$1(void); 592e1051a39Sopenharmony_ciint PEM_read_$1_ex(void); 593e1051a39Sopenharmony_ci#endif 594e1051a39Sopenharmony_ciint PEM_read_bio_$1(void); 595e1051a39Sopenharmony_ciint PEM_read_bio_$1_ex(void); 596e1051a39Sopenharmony_ciEOF 597e1051a39Sopenharmony_ci }, 598e1051a39Sopenharmony_ci }, 599e1051a39Sopenharmony_ci # Universal translator of attributed PEM declarators 600e1051a39Sopenharmony_ci { regexp => qr/ 601e1051a39Sopenharmony_ci DECLARE_PEM 602e1051a39Sopenharmony_ci ((?:_rw|_rw_cb|_rw_const|_write|_write_cb|_write_const|_read|_read_cb) 603e1051a39Sopenharmony_ci (?:_ex)?) 604e1051a39Sopenharmony_ci _attr 605e1051a39Sopenharmony_ci <<<\(\s*OSSL_DEPRECATEDIN_(.*?)\s*,(.*?)\)>>> 606e1051a39Sopenharmony_ci /x, 607e1051a39Sopenharmony_ci massager => sub { return (<<"EOF"); 608e1051a39Sopenharmony_ciDECLARE_PEM$1($3) 609e1051a39Sopenharmony_ciEOF 610e1051a39Sopenharmony_ci }, 611e1051a39Sopenharmony_ci }, 612e1051a39Sopenharmony_ci 613e1051a39Sopenharmony_ci # OpenSSL's declaration of externs with possible export linkage 614e1051a39Sopenharmony_ci # (really only relevant on Windows) 615e1051a39Sopenharmony_ci { regexp => qr/OPENSSL_(?:EXPORT|EXTERN)/, 616e1051a39Sopenharmony_ci massager => sub { return ("extern"); } 617e1051a39Sopenharmony_ci }, 618e1051a39Sopenharmony_ci 619e1051a39Sopenharmony_ci # Spurious stuff found in the OpenSSL headers 620e1051a39Sopenharmony_ci # Usually, these are just macros that expand to, well, something 621e1051a39Sopenharmony_ci { regexp => qr/__NDK_FPABI__/, 622e1051a39Sopenharmony_ci massager => sub { return (); } 623e1051a39Sopenharmony_ci }, 624e1051a39Sopenharmony_ci ); 625e1051a39Sopenharmony_ci 626e1051a39Sopenharmony_cimy $anoncnt = 0; 627e1051a39Sopenharmony_ci 628e1051a39Sopenharmony_cimy @chandlers = ( 629e1051a39Sopenharmony_ci ################################################################## 630e1051a39Sopenharmony_ci # C stuff 631e1051a39Sopenharmony_ci 632e1051a39Sopenharmony_ci # extern "C" of individual items 633e1051a39Sopenharmony_ci # Note that the main parse function has a special hack for 'extern "C" {' 634e1051a39Sopenharmony_ci # which can't be done in handlers 635e1051a39Sopenharmony_ci # We simply ignore it. 636e1051a39Sopenharmony_ci { regexp => qr/^extern "C" (.*(?:;|>>>))/, 637e1051a39Sopenharmony_ci massager => sub { return ($1); }, 638e1051a39Sopenharmony_ci }, 639e1051a39Sopenharmony_ci # any other extern is just ignored 640e1051a39Sopenharmony_ci { regexp => qr/^\s* # Any spaces before 641e1051a39Sopenharmony_ci extern # The keyword we look for 642e1051a39Sopenharmony_ci \b # word to non-word boundary 643e1051a39Sopenharmony_ci .* # Anything after 644e1051a39Sopenharmony_ci ; 645e1051a39Sopenharmony_ci /x, 646e1051a39Sopenharmony_ci massager => sub { return (); }, 647e1051a39Sopenharmony_ci }, 648e1051a39Sopenharmony_ci # union, struct and enum definitions 649e1051a39Sopenharmony_ci # Because this one might appear a little everywhere within type 650e1051a39Sopenharmony_ci # definitions, we take it out and replace it with just 651e1051a39Sopenharmony_ci # 'union|struct|enum name' while registering it. 652e1051a39Sopenharmony_ci # This makes use of the parser trick to surround the outer braces 653e1051a39Sopenharmony_ci # with <<< and >>> 654e1051a39Sopenharmony_ci { regexp => qr/(.*) # Anything before ($1) 655e1051a39Sopenharmony_ci \b # word to non-word boundary 656e1051a39Sopenharmony_ci (union|struct|enum) # The word used ($2) 657e1051a39Sopenharmony_ci (?:\s([[:alpha:]_]\w*))? # Struct or enum name ($3) 658e1051a39Sopenharmony_ci <<<(\{.*?\})>>> # Struct or enum definition ($4) 659e1051a39Sopenharmony_ci (.*) # Anything after ($5) 660e1051a39Sopenharmony_ci ; 661e1051a39Sopenharmony_ci /x, 662e1051a39Sopenharmony_ci massager => sub { 663e1051a39Sopenharmony_ci my $before = $1; 664e1051a39Sopenharmony_ci my $word = $2; 665e1051a39Sopenharmony_ci my $name = $3 666e1051a39Sopenharmony_ci || sprintf("__anon%03d", ++$anoncnt); # Anonymous struct 667e1051a39Sopenharmony_ci my $definition = $4; 668e1051a39Sopenharmony_ci my $after = $5; 669e1051a39Sopenharmony_ci my $type = $word eq "struct" ? 'S' : 'E'; 670e1051a39Sopenharmony_ci if ($before ne "" || $after ne ";") { 671e1051a39Sopenharmony_ci if ($after =~ m|^\w|) { $after = " ".$after; } 672e1051a39Sopenharmony_ci return ("$before$word $name$after;", 673e1051a39Sopenharmony_ci "$word $name", $type, "", "$word$definition", all_conds()); 674e1051a39Sopenharmony_ci } 675e1051a39Sopenharmony_ci # If there was no before nor after, make the return much simple 676e1051a39Sopenharmony_ci return ("", "$word $name", $type, "", "$word$definition", all_conds()); 677e1051a39Sopenharmony_ci } 678e1051a39Sopenharmony_ci }, 679e1051a39Sopenharmony_ci # Named struct and enum forward declarations 680e1051a39Sopenharmony_ci # We really just ignore them, but we need to parse them or the variable 681e1051a39Sopenharmony_ci # declaration handler further down will think it's a variable declaration. 682e1051a39Sopenharmony_ci { regexp => qr/^(union|struct|enum) ([[:alpha:]_]\w*);/, 683e1051a39Sopenharmony_ci massager => sub { return (); } 684e1051a39Sopenharmony_ci }, 685e1051a39Sopenharmony_ci # Function returning function pointer declaration 686e1051a39Sopenharmony_ci # This sort of declaration may have a body (inline functions, for example) 687e1051a39Sopenharmony_ci { regexp => qr/(?:(typedef)\s?)? # Possible typedef ($1) 688e1051a39Sopenharmony_ci ((?:\w|\*|\s)*?) # Return type ($2) 689e1051a39Sopenharmony_ci \s? # Possible space 690e1051a39Sopenharmony_ci <<<\(\* 691e1051a39Sopenharmony_ci ([[:alpha:]_]\w*) # Function name ($3) 692e1051a39Sopenharmony_ci (\(.*\)) # Parameters ($4) 693e1051a39Sopenharmony_ci \)>>> 694e1051a39Sopenharmony_ci <<<(\(.*\))>>> # F.p. parameters ($5) 695e1051a39Sopenharmony_ci (?:<<<\{.*\}>>>|;) # Body or semicolon 696e1051a39Sopenharmony_ci /x, 697e1051a39Sopenharmony_ci massager => sub { 698e1051a39Sopenharmony_ci return ("", $3, 'T', "", "$2(*$4)$5", all_conds()) 699e1051a39Sopenharmony_ci if defined $1; 700e1051a39Sopenharmony_ci return ("", $3, 'F', "$2(*)$5", "$2(*$4)$5", all_conds()); } 701e1051a39Sopenharmony_ci }, 702e1051a39Sopenharmony_ci # Function pointer declaration, or typedef thereof 703e1051a39Sopenharmony_ci # This sort of declaration never has a function body 704e1051a39Sopenharmony_ci { regexp => qr/(?:(typedef)\s?)? # Possible typedef ($1) 705e1051a39Sopenharmony_ci ((?:\w|\*|\s)*?) # Return type ($2) 706e1051a39Sopenharmony_ci <<<\(\*([[:alpha:]_]\w*)\)>>> # T.d. or var name ($3) 707e1051a39Sopenharmony_ci <<<(\(.*\))>>> # F.p. parameters ($4) 708e1051a39Sopenharmony_ci ; 709e1051a39Sopenharmony_ci /x, 710e1051a39Sopenharmony_ci massager => sub { 711e1051a39Sopenharmony_ci return ("", $3, 'T', "", "$2(*)$4", all_conds()) 712e1051a39Sopenharmony_ci if defined $1; 713e1051a39Sopenharmony_ci return ("", $3, 'V', "$2(*)$4", "$2(*)$4", all_conds()); 714e1051a39Sopenharmony_ci }, 715e1051a39Sopenharmony_ci }, 716e1051a39Sopenharmony_ci # Function declaration, or typedef thereof 717e1051a39Sopenharmony_ci # This sort of declaration may have a body (inline functions, for example) 718e1051a39Sopenharmony_ci { regexp => qr/(?:(typedef)\s?)? # Possible typedef ($1) 719e1051a39Sopenharmony_ci ((?:\w|\*|\s)*?) # Return type ($2) 720e1051a39Sopenharmony_ci \s? # Possible space 721e1051a39Sopenharmony_ci ([[:alpha:]_]\w*) # Function name ($3) 722e1051a39Sopenharmony_ci <<<(\(.*\))>>> # Parameters ($4) 723e1051a39Sopenharmony_ci (?:<<<\{.*\}>>>|;) # Body or semicolon 724e1051a39Sopenharmony_ci /x, 725e1051a39Sopenharmony_ci massager => sub { 726e1051a39Sopenharmony_ci return ("", $3, 'T', "", "$2$4", all_conds()) 727e1051a39Sopenharmony_ci if defined $1; 728e1051a39Sopenharmony_ci return ("", $3, 'F', $2, "$2$4", all_conds()); 729e1051a39Sopenharmony_ci }, 730e1051a39Sopenharmony_ci }, 731e1051a39Sopenharmony_ci # Variable declaration, including arrays, or typedef thereof 732e1051a39Sopenharmony_ci { regexp => qr/(?:(typedef)\s?)? # Possible typedef ($1) 733e1051a39Sopenharmony_ci ((?:\w|\*|\s)*?) # Type ($2) 734e1051a39Sopenharmony_ci \s? # Possible space 735e1051a39Sopenharmony_ci ([[:alpha:]_]\w*) # Variable name ($3) 736e1051a39Sopenharmony_ci ((?:<<<\[[^\]]*\]>>>)*) # Possible array declaration ($4) 737e1051a39Sopenharmony_ci ; 738e1051a39Sopenharmony_ci /x, 739e1051a39Sopenharmony_ci massager => sub { 740e1051a39Sopenharmony_ci return ("", $3, 'T', "", $2.($4||""), all_conds()) 741e1051a39Sopenharmony_ci if defined $1; 742e1051a39Sopenharmony_ci return ("", $3, 'V', $2.($4||""), $2.($4||""), all_conds()); 743e1051a39Sopenharmony_ci }, 744e1051a39Sopenharmony_ci }, 745e1051a39Sopenharmony_ci); 746e1051a39Sopenharmony_ci 747e1051a39Sopenharmony_ci# End handlers are almost the same as handlers, except they are run through 748e1051a39Sopenharmony_ci# ONCE when the input has been parsed through. These are used to check for 749e1051a39Sopenharmony_ci# remaining stuff, such as an unfinished #ifdef and stuff like that that the 750e1051a39Sopenharmony_ci# main parser can't check on its own. 751e1051a39Sopenharmony_cimy @endhandlers = ( 752e1051a39Sopenharmony_ci { massager => sub { 753e1051a39Sopenharmony_ci my %opts = %{$_[0]}; 754e1051a39Sopenharmony_ci 755e1051a39Sopenharmony_ci die "Unfinished preprocessor conditions levels: ",scalar(@preprocessor_conds),($opts{filename} ? " in file ".$opts{filename}: ""),$opts{PLACE} 756e1051a39Sopenharmony_ci if @preprocessor_conds; 757e1051a39Sopenharmony_ci } 758e1051a39Sopenharmony_ci } 759e1051a39Sopenharmony_ci ); 760e1051a39Sopenharmony_ci 761e1051a39Sopenharmony_ci# takes a list of strings that can each contain one or several lines of code 762e1051a39Sopenharmony_ci# also takes a hash of options as last argument. 763e1051a39Sopenharmony_ci# 764e1051a39Sopenharmony_ci# returns a list of hashes with information: 765e1051a39Sopenharmony_ci# 766e1051a39Sopenharmony_ci# name name of the thing 767e1051a39Sopenharmony_ci# type type, see the massage handler function 768e1051a39Sopenharmony_ci# returntype return type of functions and variables 769e1051a39Sopenharmony_ci# value value for macros, signature for functions, variables 770e1051a39Sopenharmony_ci# and structs 771e1051a39Sopenharmony_ci# conds preprocessor conditions (array ref) 772e1051a39Sopenharmony_ci 773e1051a39Sopenharmony_cisub parse { 774e1051a39Sopenharmony_ci my %opts; 775e1051a39Sopenharmony_ci if (ref($_[$#_]) eq "HASH") { 776e1051a39Sopenharmony_ci %opts = %{$_[$#_]}; 777e1051a39Sopenharmony_ci pop @_; 778e1051a39Sopenharmony_ci } 779e1051a39Sopenharmony_ci my %state = ( 780e1051a39Sopenharmony_ci in_extern_C => 0, # An exception to parenthesis processing. 781e1051a39Sopenharmony_ci cpp_parens => [], # A list of ending parens and braces found in 782e1051a39Sopenharmony_ci # preprocessor directives 783e1051a39Sopenharmony_ci c_parens => [], # A list of ending parens and braces found in 784e1051a39Sopenharmony_ci # C statements 785e1051a39Sopenharmony_ci in_string => "", # empty string when outside a string, otherwise 786e1051a39Sopenharmony_ci # "'" or '"' depending on the starting quote. 787e1051a39Sopenharmony_ci in_comment => "", # empty string when outside a comment, otherwise 788e1051a39Sopenharmony_ci # "/*" or "//" depending on the type of comment 789e1051a39Sopenharmony_ci # found. The latter will never be multiline 790e1051a39Sopenharmony_ci # NOTE: in_string and in_comment will never be 791e1051a39Sopenharmony_ci # true (in perl semantics) at the same time. 792e1051a39Sopenharmony_ci current_line => 0, 793e1051a39Sopenharmony_ci ); 794e1051a39Sopenharmony_ci my @result = (); 795e1051a39Sopenharmony_ci my $normalized_line = ""; # $input_line, but normalized. In essence, this 796e1051a39Sopenharmony_ci # means that ALL whitespace is removed unless 797e1051a39Sopenharmony_ci # it absolutely has to be present, and in that 798e1051a39Sopenharmony_ci # case, there's only one space. 799e1051a39Sopenharmony_ci # The cases where a space needs to stay present 800e1051a39Sopenharmony_ci # are: 801e1051a39Sopenharmony_ci # 1. between words 802e1051a39Sopenharmony_ci # 2. between words and number 803e1051a39Sopenharmony_ci # 3. after the first word of a preprocessor 804e1051a39Sopenharmony_ci # directive. 805e1051a39Sopenharmony_ci # 4. for the #define directive, between the macro 806e1051a39Sopenharmony_ci # name/args and its value, so we end up with: 807e1051a39Sopenharmony_ci # #define FOO val 808e1051a39Sopenharmony_ci # #define BAR(x) something(x) 809e1051a39Sopenharmony_ci my $collected_stmt = ""; # Where we're building up a C line until it's a 810e1051a39Sopenharmony_ci # complete definition/declaration, as determined 811e1051a39Sopenharmony_ci # by any handler being capable of matching it. 812e1051a39Sopenharmony_ci 813e1051a39Sopenharmony_ci # We use $_ shamelessly when looking through @lines. 814e1051a39Sopenharmony_ci # In case we find a \ at the end, we keep filling it up with more lines. 815e1051a39Sopenharmony_ci $_ = undef; 816e1051a39Sopenharmony_ci 817e1051a39Sopenharmony_ci foreach my $line (@_) { 818e1051a39Sopenharmony_ci # split tries to be smart when a string ends with the thing we split on 819e1051a39Sopenharmony_ci $line .= "\n" unless $line =~ m|\R$|; 820e1051a39Sopenharmony_ci $line .= "#"; 821e1051a39Sopenharmony_ci 822e1051a39Sopenharmony_ci # We use ¦undef¦ as a marker for a new line from the file. 823e1051a39Sopenharmony_ci # Since we convert one line to several and unshift that into @lines, 824e1051a39Sopenharmony_ci # that's the only safe way we have to track the original lines 825e1051a39Sopenharmony_ci my @lines = map { ( undef, $_ ) } split m|\R|, $line; 826e1051a39Sopenharmony_ci 827e1051a39Sopenharmony_ci # Remember that extra # we added above? Now we remove it 828e1051a39Sopenharmony_ci pop @lines; 829e1051a39Sopenharmony_ci pop @lines; # Don't forget the undef 830e1051a39Sopenharmony_ci 831e1051a39Sopenharmony_ci while (@lines) { 832e1051a39Sopenharmony_ci if (!defined($lines[0])) { 833e1051a39Sopenharmony_ci shift @lines; 834e1051a39Sopenharmony_ci $state{current_line}++; 835e1051a39Sopenharmony_ci if (!defined($_)) { 836e1051a39Sopenharmony_ci $opts{PLACE} = " at ".$opts{filename}." line ".$state{current_line}."\n"; 837e1051a39Sopenharmony_ci $opts{PLACE2} = $opts{filename}.":".$state{current_line}; 838e1051a39Sopenharmony_ci } 839e1051a39Sopenharmony_ci next; 840e1051a39Sopenharmony_ci } 841e1051a39Sopenharmony_ci 842e1051a39Sopenharmony_ci $_ = "" unless defined $_; 843e1051a39Sopenharmony_ci $_ .= shift @lines; 844e1051a39Sopenharmony_ci 845e1051a39Sopenharmony_ci if (m|\\$|) { 846e1051a39Sopenharmony_ci $_ = $`; 847e1051a39Sopenharmony_ci next; 848e1051a39Sopenharmony_ci } 849e1051a39Sopenharmony_ci 850e1051a39Sopenharmony_ci if ($opts{debug}) { 851e1051a39Sopenharmony_ci print STDERR "DEBUG:----------------------------\n"; 852e1051a39Sopenharmony_ci print STDERR "DEBUG: \$_ = '$_'\n"; 853e1051a39Sopenharmony_ci } 854e1051a39Sopenharmony_ci 855e1051a39Sopenharmony_ci ########################################################## 856e1051a39Sopenharmony_ci # Now that we have a full line, let's process through it 857e1051a39Sopenharmony_ci while(1) { 858e1051a39Sopenharmony_ci unless ($state{in_comment}) { 859e1051a39Sopenharmony_ci # Begin with checking if the current $normalized_line 860e1051a39Sopenharmony_ci # contains a preprocessor directive 861e1051a39Sopenharmony_ci # This is only done if we're not inside a comment and 862e1051a39Sopenharmony_ci # if it's a preprocessor directive and it's finished. 863e1051a39Sopenharmony_ci if ($normalized_line =~ m|^#| && $_ eq "") { 864e1051a39Sopenharmony_ci print STDERR "DEBUG[OPENSSL CPP]: \$normalized_line = '$normalized_line'\n" 865e1051a39Sopenharmony_ci if $opts{debug}; 866e1051a39Sopenharmony_ci $opts{debug_type} = "OPENSSL CPP"; 867e1051a39Sopenharmony_ci my @r = ( _run_handlers($normalized_line, 868e1051a39Sopenharmony_ci @opensslcpphandlers, 869e1051a39Sopenharmony_ci \%opts) ); 870e1051a39Sopenharmony_ci if (shift @r) { 871e1051a39Sopenharmony_ci # Checking if there are lines to inject. 872e1051a39Sopenharmony_ci if (@r) { 873e1051a39Sopenharmony_ci @r = split $/, (pop @r).$_; 874e1051a39Sopenharmony_ci print STDERR "DEBUG[OPENSSL CPP]: injecting '", join("', '", @r),"'\n" 875e1051a39Sopenharmony_ci if $opts{debug} && @r; 876e1051a39Sopenharmony_ci @lines = ( @r, @lines ); 877e1051a39Sopenharmony_ci 878e1051a39Sopenharmony_ci $_ = ""; 879e1051a39Sopenharmony_ci } 880e1051a39Sopenharmony_ci } else { 881e1051a39Sopenharmony_ci print STDERR "DEBUG[CPP]: \$normalized_line = '$normalized_line'\n" 882e1051a39Sopenharmony_ci if $opts{debug}; 883e1051a39Sopenharmony_ci $opts{debug_type} = "CPP"; 884e1051a39Sopenharmony_ci my @r = ( _run_handlers($normalized_line, 885e1051a39Sopenharmony_ci @cpphandlers, 886e1051a39Sopenharmony_ci \%opts) ); 887e1051a39Sopenharmony_ci if (shift @r) { 888e1051a39Sopenharmony_ci if (ref($r[0]) eq "HASH") { 889e1051a39Sopenharmony_ci push @result, shift @r; 890e1051a39Sopenharmony_ci } 891e1051a39Sopenharmony_ci 892e1051a39Sopenharmony_ci # Now, check if there are lines to inject. 893e1051a39Sopenharmony_ci # Really, this should never happen, it IS a 894e1051a39Sopenharmony_ci # preprocessor directive after all... 895e1051a39Sopenharmony_ci if (@r) { 896e1051a39Sopenharmony_ci @r = split $/, pop @r; 897e1051a39Sopenharmony_ci print STDERR "DEBUG[CPP]: injecting '", join("', '", @r),"'\n" 898e1051a39Sopenharmony_ci if $opts{debug} && @r; 899e1051a39Sopenharmony_ci @lines = ( @r, @lines ); 900e1051a39Sopenharmony_ci $_ = ""; 901e1051a39Sopenharmony_ci } 902e1051a39Sopenharmony_ci } 903e1051a39Sopenharmony_ci } 904e1051a39Sopenharmony_ci 905e1051a39Sopenharmony_ci # Note: we simply ignore all directives that no 906e1051a39Sopenharmony_ci # handler matches 907e1051a39Sopenharmony_ci $normalized_line = ""; 908e1051a39Sopenharmony_ci } 909e1051a39Sopenharmony_ci 910e1051a39Sopenharmony_ci # If the two strings end and start with a character that 911e1051a39Sopenharmony_ci # shouldn't get concatenated, add a space 912e1051a39Sopenharmony_ci my $space = 913e1051a39Sopenharmony_ci ($collected_stmt =~ m/(?:"|')$/ 914e1051a39Sopenharmony_ci || ($collected_stmt =~ m/(?:\w|\d)$/ 915e1051a39Sopenharmony_ci && $normalized_line =~ m/^(?:\w|\d)/)) ? " " : ""; 916e1051a39Sopenharmony_ci 917e1051a39Sopenharmony_ci # Now, unless we're building up a preprocessor directive or 918e1051a39Sopenharmony_ci # are in the middle of a string, or the parens et al aren't 919e1051a39Sopenharmony_ci # balanced up yet, let's try and see if there's a OpenSSL 920e1051a39Sopenharmony_ci # or C handler that can make sense of what we have so far. 921e1051a39Sopenharmony_ci if ( $normalized_line !~ m|^#| 922e1051a39Sopenharmony_ci && ($collected_stmt ne "" || $normalized_line ne "") 923e1051a39Sopenharmony_ci && ! @{$state{c_parens}} 924e1051a39Sopenharmony_ci && ! $state{in_string} ) { 925e1051a39Sopenharmony_ci if ($opts{debug}) { 926e1051a39Sopenharmony_ci print STDERR "DEBUG[OPENSSL C]: \$collected_stmt = '$collected_stmt'\n"; 927e1051a39Sopenharmony_ci print STDERR "DEBUG[OPENSSL C]: \$normalized_line = '$normalized_line'\n"; 928e1051a39Sopenharmony_ci } 929e1051a39Sopenharmony_ci $opts{debug_type} = "OPENSSL C"; 930e1051a39Sopenharmony_ci my @r = ( _run_handlers($collected_stmt 931e1051a39Sopenharmony_ci .$space 932e1051a39Sopenharmony_ci .$normalized_line, 933e1051a39Sopenharmony_ci @opensslchandlers, 934e1051a39Sopenharmony_ci \%opts) ); 935e1051a39Sopenharmony_ci if (shift @r) { 936e1051a39Sopenharmony_ci # Checking if there are lines to inject. 937e1051a39Sopenharmony_ci if (@r) { 938e1051a39Sopenharmony_ci @r = split $/, (pop @r).$_; 939e1051a39Sopenharmony_ci print STDERR "DEBUG[OPENSSL]: injecting '", join("', '", @r),"'\n" 940e1051a39Sopenharmony_ci if $opts{debug} && @r; 941e1051a39Sopenharmony_ci @lines = ( @r, @lines ); 942e1051a39Sopenharmony_ci 943e1051a39Sopenharmony_ci $_ = ""; 944e1051a39Sopenharmony_ci } 945e1051a39Sopenharmony_ci $normalized_line = ""; 946e1051a39Sopenharmony_ci $collected_stmt = ""; 947e1051a39Sopenharmony_ci } else { 948e1051a39Sopenharmony_ci if ($opts{debug}) { 949e1051a39Sopenharmony_ci print STDERR "DEBUG[C]: \$collected_stmt = '$collected_stmt'\n"; 950e1051a39Sopenharmony_ci print STDERR "DEBUG[C]: \$normalized_line = '$normalized_line'\n"; 951e1051a39Sopenharmony_ci } 952e1051a39Sopenharmony_ci $opts{debug_type} = "C"; 953e1051a39Sopenharmony_ci my @r = ( _run_handlers($collected_stmt 954e1051a39Sopenharmony_ci .$space 955e1051a39Sopenharmony_ci .$normalized_line, 956e1051a39Sopenharmony_ci @chandlers, 957e1051a39Sopenharmony_ci \%opts) ); 958e1051a39Sopenharmony_ci if (shift @r) { 959e1051a39Sopenharmony_ci if (ref($r[0]) eq "HASH") { 960e1051a39Sopenharmony_ci push @result, shift @r; 961e1051a39Sopenharmony_ci } 962e1051a39Sopenharmony_ci 963e1051a39Sopenharmony_ci # Checking if there are lines to inject. 964e1051a39Sopenharmony_ci if (@r) { 965e1051a39Sopenharmony_ci @r = split $/, (pop @r).$_; 966e1051a39Sopenharmony_ci print STDERR "DEBUG[C]: injecting '", join("', '", @r),"'\n" 967e1051a39Sopenharmony_ci if $opts{debug} && @r; 968e1051a39Sopenharmony_ci @lines = ( @r, @lines ); 969e1051a39Sopenharmony_ci 970e1051a39Sopenharmony_ci $_ = ""; 971e1051a39Sopenharmony_ci } 972e1051a39Sopenharmony_ci $normalized_line = ""; 973e1051a39Sopenharmony_ci $collected_stmt = ""; 974e1051a39Sopenharmony_ci } 975e1051a39Sopenharmony_ci } 976e1051a39Sopenharmony_ci } 977e1051a39Sopenharmony_ci if ($_ eq "") { 978e1051a39Sopenharmony_ci $collected_stmt .= $space.$normalized_line; 979e1051a39Sopenharmony_ci $normalized_line = ""; 980e1051a39Sopenharmony_ci } 981e1051a39Sopenharmony_ci } 982e1051a39Sopenharmony_ci 983e1051a39Sopenharmony_ci if ($_ eq "") { 984e1051a39Sopenharmony_ci $_ = undef; 985e1051a39Sopenharmony_ci last; 986e1051a39Sopenharmony_ci } 987e1051a39Sopenharmony_ci 988e1051a39Sopenharmony_ci # Take care of inside string first. 989e1051a39Sopenharmony_ci if ($state{in_string}) { 990e1051a39Sopenharmony_ci if (m/ (?:^|(?<!\\)) # Make sure it's not escaped 991e1051a39Sopenharmony_ci $state{in_string} # Look for matching quote 992e1051a39Sopenharmony_ci /x) { 993e1051a39Sopenharmony_ci $normalized_line .= $`.$&; 994e1051a39Sopenharmony_ci $state{in_string} = ""; 995e1051a39Sopenharmony_ci $_ = $'; 996e1051a39Sopenharmony_ci next; 997e1051a39Sopenharmony_ci } else { 998e1051a39Sopenharmony_ci die "Unfinished string without continuation found$opts{PLACE}\n"; 999e1051a39Sopenharmony_ci } 1000e1051a39Sopenharmony_ci } 1001e1051a39Sopenharmony_ci # ... or inside comments, whichever happens to apply 1002e1051a39Sopenharmony_ci elsif ($state{in_comment}) { 1003e1051a39Sopenharmony_ci 1004e1051a39Sopenharmony_ci # This should never happen 1005e1051a39Sopenharmony_ci die "Something went seriously wrong, multiline //???$opts{PLACE}\n" 1006e1051a39Sopenharmony_ci if ($state{in_comment} eq "//"); 1007e1051a39Sopenharmony_ci 1008e1051a39Sopenharmony_ci # A note: comments are simply discarded. 1009e1051a39Sopenharmony_ci 1010e1051a39Sopenharmony_ci if (m/ (?:^|(?<!\\)) # Make sure it's not escaped 1011e1051a39Sopenharmony_ci \*\/ # Look for C comment end 1012e1051a39Sopenharmony_ci /x) { 1013e1051a39Sopenharmony_ci $state{in_comment} = ""; 1014e1051a39Sopenharmony_ci $_ = $'; 1015e1051a39Sopenharmony_ci print STDERR "DEBUG: Found end of comment, followed by '$_'\n" 1016e1051a39Sopenharmony_ci if $opts{debug}; 1017e1051a39Sopenharmony_ci next; 1018e1051a39Sopenharmony_ci } else { 1019e1051a39Sopenharmony_ci $_ = ""; 1020e1051a39Sopenharmony_ci next; 1021e1051a39Sopenharmony_ci } 1022e1051a39Sopenharmony_ci } 1023e1051a39Sopenharmony_ci 1024e1051a39Sopenharmony_ci # At this point, it's safe to remove leading whites, but 1025e1051a39Sopenharmony_ci # we need to be careful with some preprocessor lines 1026e1051a39Sopenharmony_ci if (m|^\s+|) { 1027e1051a39Sopenharmony_ci my $rest = $'; 1028e1051a39Sopenharmony_ci my $space = ""; 1029e1051a39Sopenharmony_ci $space = " " 1030e1051a39Sopenharmony_ci if ($normalized_line =~ m/^ 1031e1051a39Sopenharmony_ci \#define\s\w(?:\w|\d)*(?:<<<\([^\)]*\)>>>)? 1032e1051a39Sopenharmony_ci | \#[a-z]+ 1033e1051a39Sopenharmony_ci $/x); 1034e1051a39Sopenharmony_ci print STDERR "DEBUG: Processing leading spaces: \$normalized_line = '$normalized_line', \$space = '$space', \$rest = '$rest'\n" 1035e1051a39Sopenharmony_ci if $opts{debug}; 1036e1051a39Sopenharmony_ci $_ = $space.$rest; 1037e1051a39Sopenharmony_ci } 1038e1051a39Sopenharmony_ci 1039e1051a39Sopenharmony_ci my $parens = 1040e1051a39Sopenharmony_ci $normalized_line =~ m|^#| ? 'cpp_parens' : 'c_parens'; 1041e1051a39Sopenharmony_ci (my $paren_singular = $parens) =~ s|s$||; 1042e1051a39Sopenharmony_ci 1043e1051a39Sopenharmony_ci # Now check for specific tokens, and if they are parens, 1044e1051a39Sopenharmony_ci # check them against $state{$parens}. Note that we surround 1045e1051a39Sopenharmony_ci # the outermost parens with extra "<<<" and ">>>". Those 1046e1051a39Sopenharmony_ci # are for the benefit of handlers who to need to detect 1047e1051a39Sopenharmony_ci # them, and they will be removed from the final output. 1048e1051a39Sopenharmony_ci if (m|^[\{\[\(]|) { 1049e1051a39Sopenharmony_ci my $body = $&; 1050e1051a39Sopenharmony_ci $_ = $'; 1051e1051a39Sopenharmony_ci if (!@{$state{$parens}}) { 1052e1051a39Sopenharmony_ci if ("$normalized_line$body" =~ m|^extern "C"\{$|) { 1053e1051a39Sopenharmony_ci $state{in_extern_C} = 1; 1054e1051a39Sopenharmony_ci print STDERR "DEBUG: found start of 'extern \"C\"' ($normalized_line$body)\n" 1055e1051a39Sopenharmony_ci if $opts{debug}; 1056e1051a39Sopenharmony_ci $normalized_line = ""; 1057e1051a39Sopenharmony_ci } else { 1058e1051a39Sopenharmony_ci $normalized_line .= "<<<".$body; 1059e1051a39Sopenharmony_ci } 1060e1051a39Sopenharmony_ci } else { 1061e1051a39Sopenharmony_ci $normalized_line .= $body; 1062e1051a39Sopenharmony_ci } 1063e1051a39Sopenharmony_ci 1064e1051a39Sopenharmony_ci if ($normalized_line ne "") { 1065e1051a39Sopenharmony_ci print STDERR "DEBUG: found $paren_singular start '$body'\n" 1066e1051a39Sopenharmony_ci if $opts{debug}; 1067e1051a39Sopenharmony_ci $body =~ tr|\{\[\(|\}\]\)|; 1068e1051a39Sopenharmony_ci print STDERR "DEBUG: pushing $paren_singular end '$body'\n" 1069e1051a39Sopenharmony_ci if $opts{debug}; 1070e1051a39Sopenharmony_ci push @{$state{$parens}}, $body; 1071e1051a39Sopenharmony_ci } 1072e1051a39Sopenharmony_ci } elsif (m|^[\}\]\)]|) { 1073e1051a39Sopenharmony_ci $_ = $'; 1074e1051a39Sopenharmony_ci 1075e1051a39Sopenharmony_ci if (!@{$state{$parens}} 1076e1051a39Sopenharmony_ci && $& eq '}' && $state{in_extern_C}) { 1077e1051a39Sopenharmony_ci print STDERR "DEBUG: found end of 'extern \"C\"'\n" 1078e1051a39Sopenharmony_ci if $opts{debug}; 1079e1051a39Sopenharmony_ci $state{in_extern_C} = 0; 1080e1051a39Sopenharmony_ci } else { 1081e1051a39Sopenharmony_ci print STDERR "DEBUG: Trying to match '$&' against '" 1082e1051a39Sopenharmony_ci ,join("', '", @{$state{$parens}}) 1083e1051a39Sopenharmony_ci ,"'\n" 1084e1051a39Sopenharmony_ci if $opts{debug}; 1085e1051a39Sopenharmony_ci die "Unmatched parentheses$opts{PLACE}\n" 1086e1051a39Sopenharmony_ci unless (@{$state{$parens}} 1087e1051a39Sopenharmony_ci && pop @{$state{$parens}} eq $&); 1088e1051a39Sopenharmony_ci if (!@{$state{$parens}}) { 1089e1051a39Sopenharmony_ci $normalized_line .= $&.">>>"; 1090e1051a39Sopenharmony_ci } else { 1091e1051a39Sopenharmony_ci $normalized_line .= $&; 1092e1051a39Sopenharmony_ci } 1093e1051a39Sopenharmony_ci } 1094e1051a39Sopenharmony_ci } elsif (m|^["']|) { # string start 1095e1051a39Sopenharmony_ci my $body = $&; 1096e1051a39Sopenharmony_ci $_ = $'; 1097e1051a39Sopenharmony_ci 1098e1051a39Sopenharmony_ci # We want to separate strings from \w and \d with one space. 1099e1051a39Sopenharmony_ci $normalized_line .= " " if $normalized_line =~ m/(\w|\d)$/; 1100e1051a39Sopenharmony_ci $normalized_line .= $body; 1101e1051a39Sopenharmony_ci $state{in_string} = $body; 1102e1051a39Sopenharmony_ci } elsif (m|^\/\*|) { # C style comment 1103e1051a39Sopenharmony_ci print STDERR "DEBUG: found start of C style comment\n" 1104e1051a39Sopenharmony_ci if $opts{debug}; 1105e1051a39Sopenharmony_ci $state{in_comment} = $&; 1106e1051a39Sopenharmony_ci $_ = $'; 1107e1051a39Sopenharmony_ci } elsif (m|^\/\/|) { # C++ style comment 1108e1051a39Sopenharmony_ci print STDERR "DEBUG: found C++ style comment\n" 1109e1051a39Sopenharmony_ci if $opts{debug}; 1110e1051a39Sopenharmony_ci $_ = ""; # (just discard it entirely) 1111e1051a39Sopenharmony_ci } elsif (m/^ (?| (?: 0[xX][[:xdigit:]]+ | 0[bB][01]+ | [0-9]+ ) 1112e1051a39Sopenharmony_ci (?i: U | L | UL | LL | ULL )? 1113e1051a39Sopenharmony_ci | [0-9]+\.[0-9]+(?:[eE][\-\+]\d+)? (?i: F | L)? 1114e1051a39Sopenharmony_ci ) /x) { 1115e1051a39Sopenharmony_ci print STDERR "DEBUG: Processing numbers: \$normalized_line = '$normalized_line', \$& = '$&', \$' = '$''\n" 1116e1051a39Sopenharmony_ci if $opts{debug}; 1117e1051a39Sopenharmony_ci $normalized_line .= $&; 1118e1051a39Sopenharmony_ci $_ = $'; 1119e1051a39Sopenharmony_ci } elsif (m/^[[:alpha:]_]\w*/) { 1120e1051a39Sopenharmony_ci my $body = $&; 1121e1051a39Sopenharmony_ci my $rest = $'; 1122e1051a39Sopenharmony_ci my $space = ""; 1123e1051a39Sopenharmony_ci 1124e1051a39Sopenharmony_ci # Now, only add a space if it's needed to separate 1125e1051a39Sopenharmony_ci # two \w characters, and we also surround strings with 1126e1051a39Sopenharmony_ci # a space. In this case, that's if $normalized_line ends 1127e1051a39Sopenharmony_ci # with a \w, \d, " or '. 1128e1051a39Sopenharmony_ci $space = " " 1129e1051a39Sopenharmony_ci if ($normalized_line =~ m/("|')$/ 1130e1051a39Sopenharmony_ci || ($normalized_line =~ m/(\w|\d)$/ 1131e1051a39Sopenharmony_ci && $body =~ m/^(\w|\d)/)); 1132e1051a39Sopenharmony_ci 1133e1051a39Sopenharmony_ci print STDERR "DEBUG: Processing words: \$normalized_line = '$normalized_line', \$space = '$space', \$body = '$body', \$rest = '$rest'\n" 1134e1051a39Sopenharmony_ci if $opts{debug}; 1135e1051a39Sopenharmony_ci $normalized_line .= $space.$body; 1136e1051a39Sopenharmony_ci $_ = $rest; 1137e1051a39Sopenharmony_ci } elsif (m|^(?:\\)?.|) { # Catch-all 1138e1051a39Sopenharmony_ci $normalized_line .= $&; 1139e1051a39Sopenharmony_ci $_ = $'; 1140e1051a39Sopenharmony_ci } 1141e1051a39Sopenharmony_ci } 1142e1051a39Sopenharmony_ci } 1143e1051a39Sopenharmony_ci } 1144e1051a39Sopenharmony_ci foreach my $handler (@endhandlers) { 1145e1051a39Sopenharmony_ci if ($handler->{massager}) { 1146e1051a39Sopenharmony_ci $handler->{massager}->(\%opts); 1147e1051a39Sopenharmony_ci } 1148e1051a39Sopenharmony_ci } 1149e1051a39Sopenharmony_ci return @result; 1150e1051a39Sopenharmony_ci} 1151e1051a39Sopenharmony_ci 1152e1051a39Sopenharmony_ci# arg1: line to check 1153e1051a39Sopenharmony_ci# arg2...: handlers to check 1154e1051a39Sopenharmony_ci# return undef when no handler matched 1155e1051a39Sopenharmony_cisub _run_handlers { 1156e1051a39Sopenharmony_ci my %opts; 1157e1051a39Sopenharmony_ci if (ref($_[$#_]) eq "HASH") { 1158e1051a39Sopenharmony_ci %opts = %{$_[$#_]}; 1159e1051a39Sopenharmony_ci pop @_; 1160e1051a39Sopenharmony_ci } 1161e1051a39Sopenharmony_ci my $line = shift; 1162e1051a39Sopenharmony_ci my @handlers = @_; 1163e1051a39Sopenharmony_ci 1164e1051a39Sopenharmony_ci foreach my $handler (@handlers) { 1165e1051a39Sopenharmony_ci if ($handler->{regexp} 1166e1051a39Sopenharmony_ci && $line =~ m|^$handler->{regexp}$|) { 1167e1051a39Sopenharmony_ci if ($handler->{massager}) { 1168e1051a39Sopenharmony_ci if ($opts{debug}) { 1169e1051a39Sopenharmony_ci print STDERR "DEBUG[",$opts{debug_type},"]: Trying to handle '$line'\n"; 1170e1051a39Sopenharmony_ci print STDERR "DEBUG[",$opts{debug_type},"]: (matches /\^",$handler->{regexp},"\$/)\n"; 1171e1051a39Sopenharmony_ci } 1172e1051a39Sopenharmony_ci my $saved_line = $line; 1173e1051a39Sopenharmony_ci my @massaged = 1174e1051a39Sopenharmony_ci map { s/(<<<|>>>)//g; $_ } 1175e1051a39Sopenharmony_ci $handler->{massager}->($saved_line, \%opts); 1176e1051a39Sopenharmony_ci print STDERR "DEBUG[",$opts{debug_type},"]: Got back '" 1177e1051a39Sopenharmony_ci , join("', '", @massaged), "'\n" 1178e1051a39Sopenharmony_ci if $opts{debug}; 1179e1051a39Sopenharmony_ci 1180e1051a39Sopenharmony_ci # Because we may get back new lines to be 1181e1051a39Sopenharmony_ci # injected before whatever else that follows, 1182e1051a39Sopenharmony_ci # and the injected stuff might include 1183e1051a39Sopenharmony_ci # preprocessor lines, we need to inject them 1184e1051a39Sopenharmony_ci # in @lines and set $_ to the empty string to 1185e1051a39Sopenharmony_ci # break out from the inner loops 1186e1051a39Sopenharmony_ci my $injected_lines = shift @massaged || ""; 1187e1051a39Sopenharmony_ci 1188e1051a39Sopenharmony_ci if (@massaged) { 1189e1051a39Sopenharmony_ci return (1, 1190e1051a39Sopenharmony_ci { 1191e1051a39Sopenharmony_ci name => shift @massaged, 1192e1051a39Sopenharmony_ci type => shift @massaged, 1193e1051a39Sopenharmony_ci returntype => shift @massaged, 1194e1051a39Sopenharmony_ci value => shift @massaged, 1195e1051a39Sopenharmony_ci conds => [ @massaged ] 1196e1051a39Sopenharmony_ci }, 1197e1051a39Sopenharmony_ci $injected_lines 1198e1051a39Sopenharmony_ci ); 1199e1051a39Sopenharmony_ci } else { 1200e1051a39Sopenharmony_ci print STDERR "DEBUG[",$opts{debug_type},"]: (ignore, possible side effects)\n" 1201e1051a39Sopenharmony_ci if $opts{debug} && $injected_lines eq ""; 1202e1051a39Sopenharmony_ci return (1, $injected_lines); 1203e1051a39Sopenharmony_ci } 1204e1051a39Sopenharmony_ci } 1205e1051a39Sopenharmony_ci return (1); 1206e1051a39Sopenharmony_ci } 1207e1051a39Sopenharmony_ci } 1208e1051a39Sopenharmony_ci return (0); 1209e1051a39Sopenharmony_ci} 1210