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