-while (($lib, $hdr) = each %hinc)
-{
- next if($hdr eq "NONE");
- print STDERR "Scanning header file $hdr\n" if $debug;
- open(IN, "<$hdr") || die "Can't open Header file $hdr\n";
- my $line = "", $def= "", $linenr = 0;
- while(<IN>) {
- $linenr++;
- print STDERR "line: $linenr\r" if $debug;
-
- last if(/BEGIN\s+ERROR\s+CODES/);
- if ($line ne '') {
- $_ = $line . $_;
- $line = '';
- }
-
- if (/\\$/) {
- $line = $_;
- next;
- }
-
- $cpp = 1 if /^#.*ifdef.*cplusplus/; # skip "C" declaration
- if ($cpp) {
- $cpp = 0 if /^#.*endif/;
- next;
- }
-
- next if (/^#/); # skip preprocessor directives
-
- s/\/\*.*?\*\///gs; # ignore comments
- s/{[^{}]*}//gs; # ignore {} blocks
-
- if (/{|\/\*/) { # Add a } so editor works...
- $line = $_;
- } else {
- $def .= $_;
- }
- }
-
- print STDERR " \r" if $debug;
- $defnr = 0;
- foreach (split /;/, $def) {
- $defnr++;
- print STDERR "def: $defnr\r" if $debug;
-
- s/^[\n\s]*//g;
- s/[\n\s]*$//g;
- next if(/typedef\W/);
- if (/\(\*(\w*)\([^\)]+/) {
- my $name = $1;
- $name =~ tr/[a-z]/[A-Z]/;
- $ftrans{$name} = $1;
- } elsif (/\w+\W+(\w+)\W*\(\s*\)$/s){
- # K&R C
- next ;
- } elsif (/\w+\W+\w+\W*\(.*\)$/s) {
- while (not /\(\)$/s) {
- s/[^\(\)]*\)$/\)/s;
- s/\([^\(\)]*\)\)$/\)/s;
- }
- s/\(void\)//;
- /(\w+)\W*\(\)/s;
- my $name = $1;
- $name =~ tr/[a-z]/[A-Z]/;
- $ftrans{$name} = $1;
- } elsif (/\(/ and not (/=/ or /DECLARE_STACK/)) {
- print STDERR "Header $hdr: cannot parse: $_;\n";
- }
- }
-
- print STDERR " \r" if $debug;
-
- next if $reindex;
-
- # Scan function and reason codes and store them: keep a note of the
- # maximum code used.
-
- while(<IN>) {
- if(/^#define\s+(\S+)\s+(\S+)/) {
- $name = $1;
- $code = $2;
- unless($name =~ /^${lib}_([RF])_(\w+)$/) {
- print STDERR "Invalid error code $name\n";
- next;
- }
- if($1 eq "R") {
- $rcodes{$name} = $code;
- if(!(exists $rextra{$name}) &&
- ($code > $rmax{$lib}) ) {
- $rmax{$lib} = $code;
- }
- } else {
- if($code > $fmax{$lib}) {
- $fmax{$lib} = $code;
- }
- $fcodes{$name} = $code;
- }
- }
- }
- close IN;
+# The statefile has all the previous assignments.
+&phase("Reading state");
+my $skippedstate = 0;
+if ( ! $reindex && $statefile ) {
+ open(STATE, "<$statefile") || die "Can't open $statefile, $!";
+
+ # Scan function and reason codes and store them: keep a note of the
+ # maximum code used.
+ while ( <STATE> ) {
+ next if /^#/ || /^$/;
+ my $name;
+ my $code;
+ if ( /^(.+):(\d+):\\$/ ) {
+ $name = $1;
+ $code = $2;
+ my $next = <STATE>;
+ $next =~ s/^\s*(.*)\s*$/$1/;
+ die "Duplicate define $name" if exists $strings{$name};
+ $strings{$name} = $next;
+ } elsif ( /^(\S+):(\d+):(.*)$/ ) {
+ $name = $1;
+ $code = $2;
+ die "Duplicate define $name" if exists $strings{$name};
+ $strings{$name} = $3;
+ } else {
+ die "Bad line in $statefile:\n$_\n";
+ }
+ my $lib = $name;
+ $lib =~ s/^((?:OSSL_|OPENSSL_)?[^_]{2,}).*$/$1/;
+ $lib = "SSL" if $lib =~ /TLS/;
+ if ( !defined $errorfile{$lib} ) {
+ print "Skipping $_";
+ $skippedstate++;
+ next;
+ }
+ if ( $name =~ /^(?:OSSL_|OPENSSL_)?[A-Z0-9]{2,}_R_/ ) {
+ die "$lib reason code $code collision at $name\n"
+ if $rassigned{$lib} =~ /:$code:/;
+ $rassigned{$lib} .= "$code:";
+ if ( !exists $rextra{$name} ) {
+ $rmax{$lib} = $code if $code > $rmax{$lib};
+ }
+ $rcodes{$name} = $code;
+ } elsif ( $name =~ /^(?:OSSL_|OPENSSL_)?[A-Z0-9]{2,}_F_/ ) {
+ die "$lib function code $code collision at $name\n"
+ if $fassigned{$lib} =~ /:$code:/;
+ $fassigned{$lib} .= "$code:";
+ $fmax{$lib} = $code if $code > $fmax{$lib};
+ $fcodes{$name} = $code;
+ } else {
+ die "Bad line in $statefile:\n$_\n";
+ }
+ }
+ close(STATE);
+
+ if ( $debug ) {
+ foreach my $lib ( sort keys %rmax ) {
+ print STDERR "Reason codes for ${lib}:\n";
+ if ( $rassigned{$lib} =~ m/^:(.*):$/ ) {
+ my @rassigned = sort { $a <=> $b } split( ":", $1 );
+ print STDERR " ", join(' ', @rassigned), "\n";
+ } else {
+ print STDERR " --none--\n";
+ }
+ }
+ print STDERR "\n";
+ foreach my $lib ( sort keys %fmax ) {
+ print STDERR "Function codes for ${lib}:\n";
+ if ( $fassigned{$lib} =~ m/^:(.*):$/ ) {
+ my @fassigned = sort { $a <=> $b } split( ":", $1 );
+ print STDERR " ", join(' ', @fassigned), "\n";
+ } else {
+ print STDERR " --none--\n";
+ }
+ }
+ }
+}
+
+# Scan each header file and make a list of error codes
+# and function names
+&phase("Scanning headers");
+while ( ( my $hdr, my $lib ) = each %libinc ) {
+ next if $hdr eq "NONE";
+ print STDERR " ." if $debug;
+ my $line = "";
+ my $def = "";
+ my $linenr = 0;
+ my $cpp = 0;
+
+ open(IN, "<$hdr") || die "Can't open $hdr, $!,";
+ while ( <IN> ) {
+ $linenr++;
+
+ if ( $line ne '' ) {
+ $_ = $line . $_;
+ $line = '';
+ }
+
+ if ( /\\$/ ) {
+ $line = $_;
+ next;
+ }
+
+ if ( /\/\*/ ) {
+ if ( not /\*\// ) { # multiline comment...
+ $line = $_; # ... just accumulate
+ next;
+ } else {
+ s/\/\*.*?\*\///gs; # wipe it
+ }
+ }
+
+ if ( $cpp ) {
+ $cpp++ if /^#\s*if/;
+ $cpp-- if /^#\s*endif/;
+ next;
+ }
+ $cpp = 1 if /^#.*ifdef.*cplusplus/; # skip "C" declaration
+
+ next if /^\#/; # skip preprocessor directives
+
+ s/{[^{}]*}//gs; # ignore {} blocks
+
+ if ( /\{|\/\*/ ) { # Add a so editor works...
+ $line = $_;
+ } else {
+ $def .= $_;
+ }
+ }
+
+ # Delete any DECLARE_ macros
+ my $defnr = 0;
+ $def =~ s/DECLARE_\w+\([\w,\s]+\)//gs;
+ foreach ( split /;/, $def ) {
+ $defnr++;
+ # The goal is to collect function names from function declarations.
+
+ s/^[\n\s]*//g;
+ s/[\n\s]*$//g;
+
+ # Skip over recognized non-function declarations
+ next if /typedef\W/ or /DECLARE_STACK_OF/ or /TYPEDEF_.*_OF/;
+
+ # Remove STACK_OF(foo)
+ s/STACK_OF\(\w+\)/void/;
+
+ # Reduce argument lists to empty ()
+ # fold round brackets recursively: (t(*v)(t),t) -> (t{}{},t) -> {}
+ while ( /\(.*\)/s ) {
+ s/\([^\(\)]+\)/\{\}/gs;
+ s/\(\s*\*\s*(\w+)\s*\{\}\s*\)/$1/gs; #(*f{}) -> f
+ }
+
+ # pretend as we didn't use curly braces: {} -> ()
+ s/\{\}/\(\)/gs;
+
+ # Last token just before the first () is a function name.
+ if ( /(\w+)\s*\(\).*/s ) {
+ my $name = $1;
+ $name =~ tr/[a-z]/[A-Z]/;
+ $ftrans{$name} = $1;
+ } elsif ( /[\(\)]/ and not(/=/) ) {
+ print STDERR "Header $hdr: cannot parse: $_;\n";
+ }
+ }
+
+ next if $reindex;
+
+ if ( $lib eq "SSL" && $rmax{$lib} >= 1000 ) {
+ print STDERR "SSL error codes 1000+ are reserved for alerts.\n";
+ print STDERR "Any new alerts must be added to $config.\n";
+ $errors++;
+ }
+ close IN;