mkerr.pl 22.1 KB
Newer Older
R
Rich Salz 已提交
1
#! /usr/bin/env perl
M
Matt Caswell 已提交
2
# Copyright 1999-2019 The OpenSSL Project Authors. All Rights Reserved.
R
Rich Salz 已提交
3 4 5 6 7
#
# Licensed under the OpenSSL license (the "License").  You may not use
# this file except in compliance with the License.  You can obtain a copy
# in the file LICENSE in the source distribution or at
# https://www.openssl.org/source/license.html
8

9 10 11
use strict;
use warnings;

12 13 14
use lib ".";
use configdata;

15 16 17 18 19 20 21 22
my $config       = "crypto/err/openssl.ec";
my $debug        = 0;
my $internal     = 0;
my $nowrite      = 0;
my $rebuild      = 0;
my $reindex      = 0;
my $static       = 0;
my $unref        = 0;
23
my %modules         = ();
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38

my $errors       = 0;
my @t            = localtime();
my $YEAR         = $t[5] + 1900;

sub phase
{
    my $text = uc(shift);
    print STDERR "\n---\n$text\n" if $debug;
}

sub help
{
    print STDERR <<"EOF";
mkerr.pl [options] [files...]
D
Dr. Stephen Henson 已提交
39 40 41

Options:

42 43 44 45 46 47 48
    -conf FILE  Use the named config file FILE instead of the default.

    -debug      Verbose output debugging on stderr.

    -internal   Generate code that is to be built as part of OpenSSL itself.
                Also scans internal list of files.

49 50 51 52 53 54 55
    -module M   Only useful with -internal!
                Only write files for library module M.  Whether files are
                actually written or not depends on other options, such as
                -rebuild.
                Note: this option is cumulative.  If not given at all, all
                internal modules will be considered.

56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
    -nowrite    Do not write the header/source files, even if changed.

    -rebuild    Rebuild all header and C source files, even if there
                were no changes.

    -reindex    Ignore previously assigned values (except for R records in
                the config file) and renumber everything starting at 100.

    -static     Make the load/unload functions static.

    -unref      List all unreferenced function and reason codes on stderr;
                implies -nowrite.

    -help       Show this help text.

    ...         Additional arguments are added to the file list to scan,
                if '-internal' was NOT specified on the command line.
D
Dr. Stephen Henson 已提交
73 74

EOF
75 76
}

77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
while ( @ARGV ) {
    my $arg = $ARGV[0];
    last unless $arg =~ /-.*/;
    $arg = $1 if $arg =~ /-(-.*)/;
    if ( $arg eq "-conf" ) {
        $config = $ARGV[1];
        shift @ARGV;
    } elsif ( $arg eq "-debug" ) {
        $debug = 1;
        $unref = 1;
    } elsif ( $arg eq "-internal" ) {
        $internal = 1;
    } elsif ( $arg eq "-nowrite" ) {
        $nowrite = 1;
    } elsif ( $arg eq "-rebuild" ) {
        $rebuild = 1;
    } elsif ( $arg eq "-reindex" ) {
        $reindex = 1;
    } elsif ( $arg eq "-static" ) {
        $static = 1;
    } elsif ( $arg eq "-unref" ) {
        $unref = 1;
        $nowrite = 1;
100 101 102
    } elsif ( $arg eq "-module" ) {
        shift @ARGV;
        $modules{uc $ARGV[0]} = 1;
103 104 105 106 107 108 109
    } elsif ( $arg =~ /-*h(elp)?/ ) {
        &help();
        exit;
    } elsif ( $arg =~ /-.*/ ) {
        die "Unknown option $arg; use -h for help.\n";
    }
    shift @ARGV;
110 111
}

112 113 114 115 116 117 118
my @source;
if ( $internal ) {
    die "Cannot mix -internal and -static\n" if $static;
    die "Extra parameters given.\n" if @ARGV;
    @source = ( glob('crypto/*.c'), glob('crypto/*/*.c'),
                glob('ssl/*.c'), glob('ssl/*/*.c') );
} else {
119
    die "-module isn't useful without -internal\n" if scalar keys %modules > 0;
120 121
    @source = @ARGV;
}
122

123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
# Data parsed out of the config and state files.
my %hinc;       # lib -> header
my %libinc;     # header -> lib
my %cskip;      # error_file -> lib
my %errorfile;  # lib -> error file name
my %fmax;       # lib -> max assigned function code
my %rmax;       # lib -> max assigned reason code
my %fassigned;  # lib -> colon-separated list of assigned function codes
my %rassigned;  # lib -> colon-separated list of assigned reason codes
my %fnew;       # lib -> count of new function codes
my %rnew;       # lib -> count of new reason codes
my %rextra;     # "extra" reason code -> lib
my %rcodes;     # reason-name -> value
my %ftrans;     # old name -> #define-friendly name (all caps)
my %fcodes;     # function-name -> value
my $statefile;  # state file with assigned reason and function codes
R
Rich Salz 已提交
139
my %strings;    # define -> text
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169

# Read and parse the config file
open(IN, "$config") || die "Can't open config file $config, $!,";
while ( <IN> ) {
    next if /^#/ || /^$/;
    if ( /^L\s+(\S+)\s+(\S+)\s+(\S+)/ ) {
        my $lib = $1;
        my $hdr = $2;
        my $err = $3;
        $hinc{$lib}   = $hdr;
        $libinc{$hdr} = $lib;
        $cskip{$err}  = $lib;
        next if $err eq 'NONE';
        $errorfile{$lib} = $err;
        $fmax{$lib}      = 100;
        $rmax{$lib}      = 100;
        $fassigned{$lib} = ":";
        $rassigned{$lib} = ":";
        $fnew{$lib}      = 0;
        $rnew{$lib}      = 0;
    } elsif ( /^R\s+(\S+)\s+(\S+)/ ) {
        $rextra{$1} = $2;
        $rcodes{$1} = $2;
    } elsif ( /^S\s+(\S+)/ ) {
        $statefile = $1;
    } else {
        die "Illegal config line $_\n";
    }
}
close IN;
170

171 172 173
if ( ! $statefile ) {
    $statefile = $config;
    $statefile =~ s/.ec/.txt/;
174 175
}

176 177 178 179 180 181 182 183 184 185
# 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 /^#/ || /^$/;
R
Rich Salz 已提交
186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
        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";
        }
203
        my $lib = $name;
204
        $lib =~ s/^((?:OSSL_|OPENSSL_)?[^_]{2,}).*$/$1/;
205 206 207 208 209 210
        $lib = "SSL" if $lib =~ /TLS/;
        if ( !defined $errorfile{$lib} ) {
            print "Skipping $_";
            $skippedstate++;
            next;
        }
211
        if ( $name =~ /^(?:OSSL_|OPENSSL_)?[A-Z0-9]{2,}_R_/ ) {
212 213 214 215 216 217 218
            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;
219
        } elsif ( $name =~ /^(?:OSSL_|OPENSSL_)?[A-Z0-9]{2,}_F_/ ) {
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252
            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";
            }
        }
    }
}
253

254
# Scan each header file and make a list of error codes
255
# and function names
256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286
&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
            }
        }
287

288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331
        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;

R
Rich Salz 已提交
332 333 334
        # Last token just before the first () is a function name.
        if ( /(\w+)\s*\(\).*/s ) {
            my $name = $1;
335 336 337 338 339 340 341 342 343 344 345 346 347 348 349
            $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;
350
}
351
print STDERR "\n" if $debug;
352 353 354 355 356

# Scan each C source file and look for function and reason codes
# This is done by looking for strings that "look like" function or
# reason codes: basically anything consisting of all upper case and
# numerics which has _F_ or _R_ in it and which has the name of an
357
# error library at the start.  This seems to work fine except for the
358 359 360
# oddly named structure BIO_F_CTX which needs to be ignored.
# If a code doesn't exist in list compiled from headers then mark it
# with the value "X" as a place holder to give it a value later.
361
# Store all function and reason codes found in %usedfuncs and %usedreasons
362
# so all those unreferenced can be printed out.
363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383
&phase("Scanning source");
my %usedfuncs;
my %usedreasons;
foreach my $file ( @source ) {
    # Don't parse the error source file.
    next if exists $cskip{$file};
    open( IN, "<$file" ) || die "Can't open $file, $!,";
    my $func;
    my $linenr = 0;
    print STDERR "$file:\n" if $debug;
    while ( <IN> ) {

        # skip obsoleted source files entirely!
        last if /^#error\s+obsolete/;
        $linenr++;
        if ( !/;$/ && /^\**([a-zA-Z_].*[\s*])?([A-Za-z_0-9]+)\(.*([),]|$)/ ) {
            /^([^()]*(\([^()]*\)[^()]*)*)\(/;
            $1 =~ /([A-Za-z_0-9]*)$/;
            $func = $1;
        }

384
        if ( /(((?:OSSL_|OPENSSL_)?[A-Z0-9]{2,})_F_([A-Z0-9_]+))/ ) {
385 386 387 388 389 390 391 392 393 394
            next unless exists $errorfile{$2};
            next if $1 eq "BIO_F_BUFFER_CTX";
            $usedfuncs{$1} = 1;
            if ( !exists $fcodes{$1} ) {
                print STDERR "  New function $1\n" if $debug;
                $fcodes{$1} = "X";
                $fnew{$2}++;
            }
            $ftrans{$3} = $func unless exists $ftrans{$3};
            if ( uc($func) ne $3 ) {
395
                print STDERR "ERROR: mismatch $file:$linenr $func:$3\n";
396 397 398 399 400
                $errors++;
            }
            print STDERR "  Function $1 = $fcodes{$1}\n"
              if $debug;
        }
401
        if ( /(((?:OSSL_|OPENSSL_)?[A-Z0-9]{2,})_R_[A-Z0-9_]+)/ ) {
402 403 404 405 406 407
            next unless exists $errorfile{$2};
            $usedreasons{$1} = 1;
            if ( !exists $rcodes{$1} ) {
                print STDERR "  New reason $1\n" if $debug;
                $rcodes{$1} = "X";
                $rnew{$2}++;
408
            }
409 410 411 412
            print STDERR "  Reason $1 = $rcodes{$1}\n" if $debug;
        }
    }
    close IN;
413
}
414
print STDERR "\n" if $debug;
415 416

# Now process each library in turn.
417 418 419
&phase("Writing files");
my $newstate = 0;
foreach my $lib ( keys %errorfile ) {
420
    next if ! $fnew{$lib} && ! $rnew{$lib} && ! $rebuild;
421
    next if scalar keys %modules > 0 && !$modules{$lib};
422 423 424 425
    next if $nowrite;
    print STDERR "$lib: $fnew{$lib} new functions\n" if $fnew{$lib};
    print STDERR "$lib: $rnew{$lib} new reasons\n" if $rnew{$lib};
    $newstate = 1;
426

427 428 429 430 431 432 433
    # If we get here then we have some new error codes so we
    # need to rebuild the header file and C file.

    # Make a sorted list of error and reason codes for later use.
    my @function = sort grep( /^${lib}_/, keys %fcodes );
    my @reasons  = sort grep( /^${lib}_/, keys %rcodes );

434 435 436
    # indent level for innermost preprocessor lines
    my $indent = " ";

437 438 439 440 441 442
    # Rewrite the header file

    my $hfile = $hinc{$lib};
    $hfile =~ s/.h$/err.h/ if $internal;
    open( OUT, ">$hfile" ) || die "Can't write to $hfile, $!,";
    print OUT <<"EOF";
M
Matt Caswell 已提交
443
/*
444 445 446 447 448 449 450
 * Generated by util/mkerr.pl DO NOT EDIT
 * Copyright 1995-$YEAR The OpenSSL Project Authors. All Rights Reserved.
 *
 * Licensed under the OpenSSL license (the \"License\").  You may not use
 * this file except in compliance with the License.  You can obtain a copy
 * in the file LICENSE in the source distribution or at
 * https://www.openssl.org/source/license.html
451
 */
R
Richard Levitte 已提交
452

453 454
#ifndef OPENSSL_${lib}ERR_H
# define OPENSSL_${lib}ERR_H
R
Richard Levitte 已提交
455

456
# include <openssl/symhacks.h>
457

458
EOF
459 460 461
    if ( $internal ) {
        # Declare the load function because the generate C file
        # includes "fooerr.h" not "foo.h"
462 463 464 465 466 467 468 469 470 471
        if ($lib ne "SSL" && $lib ne "ASYNC"
                && grep { $lib eq uc $_ } @disablables) {
            print OUT <<"EOF";
# include <openssl/opensslconf.h>

# ifndef OPENSSL_NO_${lib}

EOF
            $indent = "  ";
        }
472
        print OUT <<"EOF";
473
#${indent}ifdef  __cplusplus
F
FdaSilvaYY 已提交
474
extern \"C\"
475
#${indent}endif
476
int ERR_load_${lib}_strings(void);
477
EOF
478 479 480
    } else {
        print OUT <<"EOF";
# define ${lib}err(f, r) ERR_${lib}_error((f), (r), OPENSSL_FILE, OPENSSL_LINE)
481 482

EOF
483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501
        if ( ! $static ) {
            print OUT <<"EOF";

# ifdef  __cplusplus
extern \"C\" {
# endif
int ERR_load_${lib}_strings(void);
void ERR_unload_${lib}_strings(void);
void ERR_${lib}_error(int function, int reason, char *file, int line);
# ifdef  __cplusplus
}
# endif
EOF
        }
    }

    print OUT "\n/*\n * $lib function codes.\n */\n";
    foreach my $i ( @function ) {
        my $z = 48 - length($i);
502
        $z = 0 if $z < 0;
503 504 505 506 507 508 509 510 511 512 513
        if ( $fcodes{$i} eq "X" ) {
            $fassigned{$lib} =~ m/^:([^:]*):/;
            my $findcode = $1;
            $findcode = $fmax{$lib} if !defined $findcode;
            while ( $fassigned{$lib} =~ m/:$findcode:/ ) {
                $findcode++;
            }
            $fcodes{$i} = $findcode;
            $fassigned{$lib} .= "$findcode:";
            print STDERR "New Function code $i\n" if $debug;
        }
514
        printf OUT "#${indent}define $i%s $fcodes{$i}\n", " " x $z;
515
    }
516

517 518 519
    print OUT "\n/*\n * $lib reason codes.\n */\n";
    foreach my $i ( @reasons ) {
        my $z = 48 - length($i);
520
        $z = 0 if $z < 0;
521 522 523 524 525 526 527 528 529 530 531
        if ( $rcodes{$i} eq "X" ) {
            $rassigned{$lib} =~ m/^:([^:]*):/;
            my $findcode = $1;
            $findcode = $rmax{$lib} if !defined $findcode;
            while ( $rassigned{$lib} =~ m/:$findcode:/ ) {
                $findcode++;
            }
            $rcodes{$i} = $findcode;
            $rassigned{$lib} .= "$findcode:";
            print STDERR "New Reason code $i\n" if $debug;
        }
532
        printf OUT "#${indent}define $i%s $rcodes{$i}\n", " " x $z;
533 534 535
    }
    print OUT "\n";

536 537 538 539
    while (length($indent) > 0) {
        $indent = substr $indent, 0, -1;
        print OUT "#${indent}endif\n";
    }
540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559

    # Rewrite the C source file containing the error details.

    # First, read any existing reason string definitions:
    my $cfile = $errorfile{$lib};
    my $pack_lib = $internal ? "ERR_LIB_${lib}" : "0";
    my $hincf = $hfile;
    $hincf =~ s|.*include/||;
    if ( $hincf =~ m|^openssl/| ) {
        $hincf = "<${hincf}>";
    } else {
        $hincf = "\"${hincf}\"";
    }

    open( OUT, ">$cfile" )
        || die "Can't open $cfile for writing, $!, stopped";

    my $const = $internal ? 'const ' : '';

    print OUT <<"EOF";
R
Rich Salz 已提交
560
/*
R
Rich Salz 已提交
561 562
 * Generated by util/mkerr.pl DO NOT EDIT
 * Copyright 1995-$YEAR The OpenSSL Project Authors. All Rights Reserved.
563
 *
R
Rich Salz 已提交
564 565 566 567
 * Licensed under the OpenSSL license (the "License").  You may not use
 * this file except in compliance with the License.  You can obtain a copy
 * in the file LICENSE in the source distribution or at
 * https://www.openssl.org/source/license.html
568 569 570
 */

#include <openssl/err.h>
571
#include $hincf
572

573
#ifndef OPENSSL_NO_ERR
574

575
static ${const}ERR_STRING_DATA ${lib}_str_functs[] = {
576
EOF
577 578 579 580

    # Add each function code: if a function name is found then use it.
    foreach my $i ( @function ) {
        my $fn;
R
Rich Salz 已提交
581 582 583 584 585 586 587 588 589
        if ( exists $strings{$i} and $strings{$i} ne '' ) {
            $fn = $strings{$i};
            $fn = "" if $fn eq '*';
        } else {
            $i =~ /^${lib}_F_(\S+)$/;
            $fn = $1;
            $fn = $ftrans{$fn} if exists $ftrans{$fn};
            $strings{$i} = $fn;
        }
590 591 592 593 594 595 596 597
        my $short = "    {ERR_PACK($pack_lib, $i, 0), \"$fn\"},";
        if ( length($short) <= 80 ) {
            print OUT "$short\n";
        } else {
            print OUT "    {ERR_PACK($pack_lib, $i, 0),\n     \"$fn\"},\n";
        }
    }
    print OUT <<"EOF";
M
Matt Caswell 已提交
598 599
    {0, NULL}
};
600

601
static ${const}ERR_STRING_DATA ${lib}_str_reasons[] = {
602
EOF
603 604 605 606

    # Add each reason code.
    foreach my $i ( @reasons ) {
        my $rn;
R
Rich Salz 已提交
607 608 609
        if ( exists $strings{$i} ) {
            $rn = $strings{$i};
            $rn = "" if $rn eq '*';
610 611 612 613
        } else {
            $i =~ /^${lib}_R_(\S+)$/;
            $rn = $1;
            $rn =~ tr/_[A-Z]/ [a-z]/;
R
Rich Salz 已提交
614
            $strings{$i} = $rn;
615 616 617 618 619 620 621 622 623
        }
        my $short = "    {ERR_PACK($pack_lib, 0, $i), \"$rn\"},";
        if ( length($short) <= 80 ) {
            print OUT "$short\n";
        } else {
            print OUT "    {ERR_PACK($pack_lib, 0, $i),\n    \"$rn\"},\n";
        }
    }
    print OUT <<"EOF";
M
Matt Caswell 已提交
624 625
    {0, NULL}
};
626 627

#endif
628 629 630
EOF
    if ( $internal ) {
        print OUT <<"EOF";
631

632
int ERR_load_${lib}_strings(void)
M
Matt Caswell 已提交
633
{
634
#ifndef OPENSSL_NO_ERR
M
Matt Caswell 已提交
635
    if (ERR_func_error_string(${lib}_str_functs[0].error) == NULL) {
636 637
        ERR_load_strings_const(${lib}_str_functs);
        ERR_load_strings_const(${lib}_str_reasons);
M
Matt Caswell 已提交
638
    }
639
#endif
640
    return 1;
M
Matt Caswell 已提交
641
}
642
EOF
643 644 645
    } else {
        my $st = $static ? "static " : "";
        print OUT <<"EOF";
646

647 648
static int lib_code = 0;
static int error_loaded = 0;
649

650
${st}int ERR_load_${lib}_strings(void)
M
Matt Caswell 已提交
651
{
652 653
    if (lib_code == 0)
        lib_code = ERR_get_next_error_library();
654

655
    if (!error_loaded) {
656
#ifndef OPENSSL_NO_ERR
657 658
        ERR_load_strings(lib_code, ${lib}_str_functs);
        ERR_load_strings(lib_code, ${lib}_str_reasons);
659
#endif
660
        error_loaded = 1;
M
Matt Caswell 已提交
661
    }
662
    return 1;
M
Matt Caswell 已提交
663
}
664

665
${st}void ERR_unload_${lib}_strings(void)
M
Matt Caswell 已提交
666
{
667
    if (error_loaded) {
668
#ifndef OPENSSL_NO_ERR
669 670
        ERR_unload_strings(lib_code, ${lib}_str_functs);
        ERR_unload_strings(lib_code, ${lib}_str_reasons);
671
#endif
672
        error_loaded = 0;
M
Matt Caswell 已提交
673 674
    }
}
675

676
${st}void ERR_${lib}_error(int function, int reason, char *file, int line)
M
Matt Caswell 已提交
677
{
678 679 680
    if (lib_code == 0)
        lib_code = ERR_get_next_error_library();
    ERR_PUT_error(lib_code, function, reason, file, line);
M
Matt Caswell 已提交
681
}
682 683
EOF

684
    }
685

686
    close OUT;
687 688
}

689
&phase("Ending");
690
# Make a list of unreferenced function and reason codes
691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711
if ( $unref ) {
    my @funref;
    foreach ( keys %fcodes ) {
        push( @funref, $_ ) unless exists $usedfuncs{$_};
    }
    my @runref;
    foreach ( keys %rcodes ) {
        push( @runref, $_ ) unless exists $usedreasons{$_};
    }
    if ( @funref ) {
        print STDERR "The following function codes were not referenced:\n";
        foreach ( sort @funref ) {
            print STDERR "  $_\n";
        }
    }
    if ( @runref ) {
        print STDERR "The following reason codes were not referenced:\n";
        foreach ( sort @runref ) {
            print STDERR "  $_\n";
        }
    }
712 713
}

714
die "Found $errors errors, quitting" if $errors;
B
Ben Laurie 已提交
715

716 717 718 719
# Update the state file
if ( $newstate )  {
    open(OUT, ">$statefile.new")
        || die "Can't write $statefile.new, $!";
720
    print OUT <<"EOF";
721
# Copyright 1999-$YEAR The OpenSSL Project Authors. All Rights Reserved.
722 723 724 725 726 727 728
#
# Licensed under the OpenSSL license (the "License").  You may not use
# this file except in compliance with the License.  You can obtain a copy
# in the file LICENSE in the source distribution or at
# https://www.openssl.org/source/license.html
EOF
    print OUT "\n# Function codes\n";
729
    foreach my $i ( sort keys %fcodes ) {
R
Rich Salz 已提交
730 731 732 733
        my $short = "$i:$fcodes{$i}:";
        my $t = exists $strings{$i} ? $strings{$i} : "";
        $t = "\\\n\t" . $t if length($short) + length($t) > 80;
        print OUT "$short$t\n";
734
    }
R
Rich Salz 已提交
735
    print OUT "\n#Reason codes\n";
736
    foreach my $i ( sort keys %rcodes ) {
R
Rich Salz 已提交
737 738 739 740
        my $short = "$i:$rcodes{$i}:";
        my $t = exists $strings{$i} ? "$strings{$i}" : "";
        $t = "\\\n\t" . $t if length($short) + length($t) > 80;
        print OUT "$short$t\n" if !exists $rextra{$i};
741 742 743 744 745 746 747 748 749 750
    }
    close(OUT);
    if ( $skippedstate ) {
        print "Skipped state, leaving update in $statefile.new";
    } else {
        rename "$statefile", "$statefile.old"
            || die "Can't backup $statefile to $statefile.old, $!";
        rename "$statefile.new", "$statefile"
            || die "Can't rename $statefile to $statefile.new, $!";
    }
B
Ben Laurie 已提交
751
}
R
Rich Salz 已提交
752

753
exit;