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