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