aboutsummaryrefslogtreecommitdiff
path: root/gcc/tree.c
AgeCommit message (Expand)AuthorFilesLines
2004-07-25c-common.h (c_staticp): Change return type from int to bool.Bernardo Innocenti1-7/+7
2004-07-23expr.c (expand_expr_real_1): Don't handle non-local variables.Richard Henderson1-3/+1
2004-07-22tree-cfg.c (gimplify_val): Move from tree-complex.c.Paolo Bonzini1-29/+39
2004-07-20rtl.h (plus_constant): Delete.Zack Weinberg1-4/+2
2004-07-20tree.h (binfo_member): Remove.Nathan Sidwell1-15/+0
2004-07-20tree.h: Include vec.hNathan Sidwell1-16/+6
2004-07-14input.h: If USE_MAPPED_LOCATION...Per Bothner1-1/+2
2004-07-13Makefile.in (OBJS-common): Add tree-data-ref.o.Sebastian Pop1-0/+61
2004-07-11re PR tree-optimization/16383 (internal compiler error: in generate_element_c...Richard Henderson1-0/+45
2004-07-10tree-ssa-loop-im.c: New file.Zdenek Dvorak1-0/+28
2004-07-08c-decl.c (pop_scope): Do not set DECL_CONTEXT on file-scope decls when...Zack Weinberg1-14/+2
2004-07-08re PR c/2511 (-pedantic not warning about bitfield overflow)Joseph Myers1-0/+22
2004-07-08except.c (expand_eh_region_start, [...]): Remove.Richard Henderson1-5/+0
2004-07-08Introduce H8SX support.Alexandre Oliva1-0/+5
2004-07-05langhooks-def.h (LANG_HOOKS_TREE_INLINING_VAR_MOD_TYPE_P): Extra arg.Richard Kenner1-31/+58
2004-07-05langhooks.c: Don't include gt-langhooks.h.Zack Weinberg1-2/+14
2004-07-05c-tree.h (TYPE_ACTUAL_ARG_TYPES): Use TYPE_LANG_SLOT_1.Nathan Sidwell1-0/+40
2004-07-03tree.c (type_hash_eq): Allow TYPE_MIN_VALUE which compares equal with tree_in...Joseph Myers1-1/+1
2004-07-02c-decl.c (grokdeclarator): Don't frob current_function_decl around variable_s...Richard Henderson1-26/+1
2004-07-01tree.def (RTL_EXPR): Remove.Richard Henderson1-21/+1
2004-06-30Conditionally compile support for --enable-mapped_location.Per Bothner1-0/+26
2004-06-28tree.def (REALPART_EXPR, [...]): Change class to 'r'.Richard Henderson1-0/+2
2004-06-28cp-tree.h (VAR_OR_FUNCTION_DECL_CHECK, [...]): Use appropriate TREE_CHECK mac...Nathan Sidwell1-58/+63
2004-06-26c-common.c (c_safe_from_p, [...]): Deleted.Richard Kenner1-0/+4
2004-06-23Makefile.in (tree-vn.o): New.Diego Novillo1-1/+4
2004-06-21alias.c (adjust_offset_for_component_ref): Use component_ref_field_offset.Richard Kenner1-53/+79
2004-06-21fold-const.c (operand_equal_p): Pass flags in recursive calls for binary and ...Roger Sayle1-0/+7
2004-06-15tree-flow-inline.h (stmt_ann): Remove use of is_essa_node.Daniel Berlin1-35/+2
2004-06-10re PR c++/14791 (13070 does not fix -Wformat with fprintf)Jakub Jelinek1-0/+1
2004-06-07* tree.c (iterative_hash_expr): Use real_hash.J"orn Rennecke1-2/+5
2004-05-21tree.c (array_type_nelts, [...]): Replace build with build2.Roger Sayle1-7/+8
2004-05-20re PR middle-end/3074 (Statement with no effect not flagged with -Wall)Roger Sayle1-9/+0
2004-05-14tree.def (documentation): Remove mention of class 'b'.Zack Weinberg1-11/+4
2004-05-13Merge tree-ssa-20020619-branch into mainline.Diego Novillo1-182/+287
2004-05-05re PR target/14899 (wrong code due to change in compatibility rules for vecto...Paolo Bonzini1-11/+34
2004-04-25PR/c++ 15119Richard Kenner1-1/+14
2004-04-12c-decl.c (finish_decl): Make a decl_stmt for a variable-sized TYPE_DECL.Richard Kenner1-14/+38
2004-04-05tree.c (reconstruct_complex_type): Use TYPE_READONLY and TYPE_VOLATILE.Andrew Pinski1-2/+2
2004-04-05c-decl.c (build_compound_literal): Use TYPE_READONLY.Richard Kenner1-4/+6
2004-04-01expr.c (get_inner_reference): Use DECL_UNSIGNED, not TREE_UNSIGNED.Richard Kenner1-4/+4
2004-03-31builtins.c, [...]: Change most occurrences of TREE_UNSIGNED to TYPE_UNSIGNED.Richard Kenner1-18/+17
2004-03-23PR 12267, 12391, 12560, 13129, 14114, 14113Zack Weinberg1-3/+15
2004-03-23alias.c (get_alias_set): Add support for TYPE_REF_CAN_ALIAS_ALL.Richard Kenner1-27/+69
2004-03-21alias.c (get_alias_set): Remove handling of PLACEHOLDER_EXPR.Richard Kenner1-24/+127
2004-03-20alias.c, [...]: Replace calls via (*targetm.foo) () with targetm.foo ().Kazu Hirata1-2/+2
2004-03-19* tree.c (substitute_in_expr): Rewrite to simplify and be more generic.Richard Kenner1-143/+74
2004-03-19langhooks-def.h (LANG_HOOKS_HASH_TYPES): New macro and hook.Richard Kenner1-26/+19
2004-03-18Fix typo in comment.Richard Kenner1-1/+1
2004-03-18tree.h (TREE_CHECK2, [...]): New macros.Richard Kenner1-25/+129
2004-03-16c-common.c (c_common_type_for_mode): Build vector types on demand.Paolo Bonzini1-42/+23
n666'>666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725
#! /usr/bin/env perl
# Copyright 1999-2018 The OpenSSL Project Authors. All Rights Reserved.
#
# Licensed under the Apache License 2.0 (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

use strict;
use warnings;

use lib ".";
use configdata;

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;
my %modules         = ();

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...]

Options:

    -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.

    -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.

    -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.

EOF
}

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;
    } elsif ( $arg eq "-module" ) {
        shift @ARGV;
        $modules{uc $ARGV[0]} = 1;
    } elsif ( $arg =~ /-*h(elp)?/ ) {
        &help();
        exit;
    } elsif ( $arg =~ /-.*/ ) {
        die "Unknown option $arg; use -h for help.\n";
    }
    shift @ARGV;
}

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'), glob('providers/*.c'),
                glob('providers/*/*.c'), glob('providers/*/*/*.c') );
} else {
    die "-module isn't useful without -internal\n" if scalar keys %modules > 0;
    @source = @ARGV;
}

# Data parsed out of the config and state files.
# We always map function-code values to zero, so items marked below with
# an asterisk could eventually be removed.  TODO(4.0)
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
my %strings;    # define -> text

# 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;

if ( ! $statefile ) {
    $statefile = $config;
    $statefile =~ s/.ec/.txt/;
}

# 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_/ ) {
            $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;
}
print STDERR "\n" if $debug;

# 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
# error library at the start.  This seems to work fine except for the
# 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.
# Store all function and reason codes found in %usedfuncs and %usedreasons
# so all those unreferenced can be printed out.
&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;
        }

        if ( /(((?:OSSL_|OPENSSL_)?[A-Z0-9]{2,})_F_([A-Z0-9_]+))/ ) {
            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};
            print STDERR "  Function $1 = $fcodes{$1}\n"
              if $debug;
        }
        if ( /(((?:OSSL_|OPENSSL_)?[A-Z0-9]{2,})_R_[A-Z0-9_]+)/ ) {
            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}++;
            }
            print STDERR "  Reason $1 = $rcodes{$1}\n" if $debug;
        }
    }
    close IN;
}
print STDERR "\n" if $debug;

# Now process each library in turn.
&phase("Writing files");
my $newstate = 0;
foreach my $lib ( keys %errorfile ) {
    next if ! $fnew{$lib} && ! $rnew{$lib} && ! $rebuild;
    next if scalar keys %modules > 0 && !$modules{$lib};
    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;

    # 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 );

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

    # 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";
/*
 * Generated by util/mkerr.pl DO NOT EDIT
 * Copyright 1995-$YEAR The OpenSSL Project Authors. All Rights Reserved.
 *
 * Licensed under the Apache License 2.0 (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
 */

#ifndef HEADER_${lib}ERR_H
# define HEADER_${lib}ERR_H

# include <openssl/opensslconf.h>
# include <openssl/symhacks.h>


EOF
    if ( $internal ) {
        # Declare the load function because the generate C file
        # includes "fooerr.h" not "foo.h"
        if ($lib ne "SSL" && $lib ne "ASYNC"
                && (grep { $lib eq uc $_ } @disablables, @disablables_int)) {
            print OUT <<"EOF";
# include <openssl/opensslconf.h>

# ifndef OPENSSL_NO_${lib}

EOF
            $indent = "  ";
        }
        print OUT <<"EOF";
#${indent}ifdef  __cplusplus
extern \"C\"
#${indent}endif
int ERR_load_${lib}_strings(void);
EOF
    } else {
        print OUT <<"EOF";
# define ${lib}err(f, r) ERR_${lib}_error(0, (r), OPENSSL_FILE, OPENSSL_LINE)

EOF
        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";
    print OUT "# if !OPENSSL_API_3\n";
    foreach my $i ( @function ) {
        my $z = 48 - length($i);
        $z = 0 if $z < 0;
        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;
        }
        printf OUT "#${indent} define $i%s 0\n", " " x $z;
    }
    print OUT "# endif\n";

    print OUT "\n/*\n * $lib reason codes.\n */\n";
    foreach my $i ( @reasons ) {
        my $z = 48 - length($i);
        $z = 0 if $z < 0;
        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;
        }
        printf OUT "#${indent}define $i%s $rcodes{$i}\n", " " x $z;
    }
    print OUT "\n";

    while (length($indent) > 0) {
        $indent = substr $indent, 0, -1;
        print OUT "#${indent}endif\n";
    }

    # 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";
/*
 * Generated by util/mkerr.pl DO NOT EDIT
 * Copyright 1995-$YEAR The OpenSSL Project Authors. All Rights Reserved.
 *
 * Licensed under the Apache License 2.0 (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
 */

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

#ifndef OPENSSL_NO_ERR

static ${const}ERR_STRING_DATA ${lib}_str_reasons[] = {
EOF

    # Add each reason code.
    foreach my $i ( @reasons ) {
        my $rn;
        if ( exists $strings{$i} ) {
            $rn = $strings{$i};
            $rn = "" if $rn eq '*';
        } else {
            $i =~ /^${lib}_R_(\S+)$/;
            $rn = $1;
            $rn =~ tr/_[A-Z]/ [a-z]/;
            $strings{$i} = $rn;
        }
        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";
    {0, NULL}
};

#endif
EOF
    if ( $internal ) {
        print OUT <<"EOF";

int ERR_load_${lib}_strings(void)
{
#ifndef OPENSSL_NO_ERR
    if (ERR_func_error_string(${lib}_str_reasons[0].error) == NULL)
        ERR_load_strings_const(${lib}_str_reasons);
#endif
    return 1;
}
EOF
    } else {
        my $st = $static ? "static " : "";
        print OUT <<"EOF";

static int lib_code = 0;
static int error_loaded = 0;

${st}int ERR_load_${lib}_strings(void)
{
    if (lib_code == 0)
        lib_code = ERR_get_next_error_library();

    if (!error_loaded) {
#ifndef OPENSSL_NO_ERR
        ERR_load_strings(lib_code, ${lib}_str_reasons);
#endif
        error_loaded = 1;
    }
    return 1;
}

${st}void ERR_unload_${lib}_strings(void)
{
    if (error_loaded) {
#ifndef OPENSSL_NO_ERR
        ERR_unload_strings(lib_code, ${lib}_str_reasons);
#endif
        error_loaded = 0;
    }
}

${st}void ERR_${lib}_error(int function, int reason, char *file, int line)
{
    if (lib_code == 0)
        lib_code = ERR_get_next_error_library();
    ERR_raise(lib_code, reason);
    ERR_set_debug(file, line, NULL);
}
EOF

    }

    close OUT;
}

&phase("Ending");
# Make a list of unreferenced function and reason codes
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";
        }
    }
}

die "Found $errors errors, quitting" if $errors;

# Update the state file
if ( $newstate )  {
    open(OUT, ">$statefile.new")
        || die "Can't write $statefile.new, $!";
    print OUT <<"EOF";
# Copyright 1999-$YEAR The OpenSSL Project Authors. All Rights Reserved.
#
# Licensed under the Apache License 2.0 (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";
    foreach my $i ( sort keys %fcodes ) {
        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";
    }
    print OUT "\n#Reason codes\n";
    foreach my $i ( sort keys %rcodes ) {
        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};
    }
    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, $!";
    }
}

exit;