Update the TLSv1.3 version indicator for draft-19
[openssl.git] / util / mkerr.pl
1 #! /usr/bin/env perl
2 # Copyright 1999-2016 The OpenSSL Project Authors. All Rights Reserved.
3 #
4 # Licensed under the OpenSSL license (the "License").  You may not use
5 # this file except in compliance with the License.  You can obtain a copy
6 # in the file LICENSE in the source distribution or at
7 # https://www.openssl.org/source/license.html
8
9 my $config = "crypto/err/openssl.ec";
10 my $debug = 0;
11 my $unref = 0;
12 my $rebuild = 0;
13 my $static = 1;
14 my $recurse = 0;
15 my $reindex = 0;
16 my $dowrite = 0;
17 my $staticloader = "";
18 my @t = localtime();
19 my $YEAR = @t[5] + 1900;
20
21 my $pack_errcode;
22 my $load_errcode;
23
24 my $errcount;
25 my $year = (localtime)[5] + 1900;
26
27 while (@ARGV) {
28         my $arg = $ARGV[0];
29         if($arg eq "-conf") {
30                 shift @ARGV;
31                 $config = shift @ARGV;
32         } elsif($arg eq "-hprefix") {
33                 shift @ARGV;
34                 $hprefix = shift @ARGV;
35         } elsif($arg eq "-debug") {
36                 $debug = 1;
37                 $unref = 1;
38                 shift @ARGV;
39         } elsif($arg eq "-rebuild") {
40                 $rebuild = 1;
41                 shift @ARGV;
42         } elsif($arg eq "-recurse") {
43                 $recurse = 1;
44                 shift @ARGV;
45         } elsif($arg eq "-reindex") {
46                 $reindex = 1;
47                 shift @ARGV;
48         } elsif($arg eq "-nostatic") {
49                 $static = 0;
50                 shift @ARGV;
51         } elsif($arg eq "-staticloader") {
52                 $staticloader = "static ";
53                 shift @ARGV;
54         } elsif($arg eq "-unref") {
55                 $unref = 1;
56                 shift @ARGV;
57         } elsif($arg eq "-write") {
58                 $dowrite = 1;
59                 shift @ARGV;
60         } elsif($arg eq "-help" || $arg eq "-h" || $arg eq "-?" || $arg eq "--help") {
61                 print STDERR <<"EOF";
62 mkerr.pl [options] ...
63
64 Options:
65
66   -conf F       Use the config file F instead of the default one:
67                   crypto/err/openssl.ec
68
69   -hprefix P    Prepend the filenames in generated #include <header>
70                 statements with prefix P. Default: 'openssl/' (without
71                 the quotes, naturally)
72                 NOTE: not used any more because our include directory
73                 structure has changed.
74
75   -debug        Turn on debugging verbose output on stderr.
76
77   -rebuild      Rebuild all header and C source files, irrespective of the
78                 fact if any error or function codes have been added/removed.
79                 Default: only update files for libraries which saw change
80                          (of course, this requires '-write' as well, or no
81                           files will be touched!)
82
83   -recurse      scan a preconfigured set of directories / files for error and
84                 function codes:
85                   (<crypto/*.c>, <crypto/*/*.c>, <ssl/*.c>, <apps/*.c>)
86                 When this option is NOT specified, the filelist is taken from
87                 the commandline instead. Here, wildcards may be embedded. (Be
88                 sure to escape those to prevent the shell from expanding them
89                 for you when you wish mkerr.pl to do so instead.)
90                 Default: take file list to scan from the command line.
91
92   -reindex      Discard the numeric values previously assigned to the error
93                 and function codes as extracted from the scanned header files;
94                 instead renumber all of them starting from 100. (Note that
95                 the numbers assigned through 'R' records in the config file
96                 remain intact.)
97                 Default: keep previously assigned numbers. (You are warned
98                          when collisions are detected.)
99
100   -nostatic     Generates a different source code, where these additional
101                 functions are generated for each library specified in the
102                 config file:
103                   void ERR_load_<LIB>_strings(void);
104                   void ERR_unload_<LIB>_strings(void);
105                   void ERR_<LIB>_error(int f, int r, char *fn, int ln);
106                   #define <LIB>err(f,r) ERR_<LIB>_error(f,r,OPENSSL_FILE,OPENSSL_LINE)
107                 while the code facilitates the use of these in an environment
108                 where the error support routines are dynamically loaded at
109                 runtime.
110                 Default: 'static' code generation.
111
112   -staticloader Prefix generated functions with the 'static' scope modifier.
113                 Default: don't write any scope modifier prefix.
114
115   -unref        Print out unreferenced function and reason codes.
116
117   -write        Actually (over)write the generated code to the header and C
118                 source files as assigned to each library through the config
119                 file.
120                 Default: don't write.
121
122   -help / -h / -? / --help            Show this help text.
123
124   ...           Additional arguments are added to the file list to scan,
125                 assuming '-recurse' was NOT specified on the command line.
126
127 EOF
128                 exit 1;
129         } else {
130                 last;
131         }
132 }
133
134 if($recurse) {
135         @source = ( <crypto/*.c>, <crypto/*/*.c>, <ssl/*.c>, <ssl/*/*.c> )
136 } else {
137         @source = @ARGV;
138 }
139
140 # Read in the config file
141
142 open(IN, "<$config") || die "Can't open config file $config";
143
144 # Parse config file
145
146 while(<IN>)
147 {
148         if(/^L\s+(\S+)\s+(\S+)\s+(\S+)/) {
149                 $hinc{$1} = $2;
150                 $libinc{$2} = $1;
151                 $cskip{$3} = $1;
152                 if($3 ne "NONE") {
153                         $csrc{$1} = $3;
154                         $fmax{$1} = 100;
155                         $rmax{$1} = 100;
156                         $fassigned{$1} = ":";
157                         $rassigned{$1} = ":";
158                         $fnew{$1} = 0;
159                         $rnew{$1} = 0;
160                 }
161         } elsif (/^F\s+(\S+)/) {
162         # Add extra function with $1
163         } elsif (/^R\s+(\S+)\s+(\S+)/) {
164                 $rextra{$1} = $2;
165                 $rcodes{$1} = $2;
166         }
167 }
168
169 close IN;
170
171 # Scan each header file in turn and make a list of error codes
172 # and function names
173
174 while (($hdr, $lib) = each %libinc)
175 {
176         next if($hdr eq "NONE");
177         print STDERR "Scanning header file $hdr\n" if $debug;
178         my $line = "", $def= "", $linenr = 0, $gotfile = 0, $cpp = 0;
179         if (open(IN, "<$hdr")) {
180             $gotfile = 1;
181             while(<IN>) {
182                 $linenr++;
183                 print STDERR "line: $linenr\r" if $debug;
184
185                 last if(/BEGIN\s+ERROR\s+CODES/);
186                 if ($line ne '') {
187                     $_ = $line . $_;
188                     $line = '';
189                 }
190
191                 if (/\\$/) {
192                     $line = $_;
193                     next;
194                 }
195
196                 if(/\/\*/) {
197                     if (not /\*\//) {           # multiline comment...
198                         $line = $_;             # ... just accumulate
199                         next;
200                     } else {
201                         s/\/\*.*?\*\///gs;      # wipe it
202                     }
203                 }
204
205                 if ($cpp) {
206                     $cpp++ if /^#\s*if/;
207                     $cpp-- if /^#\s*endif/;
208                     next;
209                 }
210                 $cpp = 1 if /^#.*ifdef.*cplusplus/;  # skip "C" declaration
211
212                 next if (/^\#/);                      # skip preprocessor directives
213
214                 s/{[^{}]*}//gs;                      # ignore {} blocks
215
216                 if (/\{|\/\*/) { # Add a } so editor works...
217                     $line = $_;
218                 } else {
219                     $def .= $_;
220                 }
221             }
222         }
223
224         print STDERR "                                  \r" if $debug;
225         $defnr = 0;
226         # Delete any DECLARE_ macros
227         $def =~ s/DECLARE_\w+\([\w,\s]+\)//gs;
228         foreach (split /;/, $def) {
229             $defnr++;
230             print STDERR "def: $defnr\r" if $debug;
231
232             # The goal is to collect function names from function declarations.
233
234             s/^[\n\s]*//g;
235             s/[\n\s]*$//g;
236
237             # Skip over recognized non-function declarations
238             next if(/typedef\W/ or /DECLARE_STACK_OF/ or /TYPEDEF_.*_OF/);
239
240             # Remove STACK_OF(foo)
241             s/STACK_OF\(\w+\)/void/;
242
243             # Reduce argument lists to empty ()
244             # fold round brackets recursively: (t(*v)(t),t) -> (t{}{},t) -> {}
245             while(/\(.*\)/s) {
246                 s/\([^\(\)]+\)/\{\}/gs;
247                 s/\(\s*\*\s*(\w+)\s*\{\}\s*\)/$1/gs;    #(*f{}) -> f
248             }
249             # pretend as we didn't use curly braces: {} -> ()
250             s/\{\}/\(\)/gs;
251
252             if (/(\w+)\s*\(\).*/s) {    # first token prior [first] () is
253                 my $name = $1;          # a function name!
254                 $name =~ tr/[a-z]/[A-Z]/;
255                 $ftrans{$name} = $1;
256             } elsif (/[\(\)]/ and not (/=/)) {
257                 print STDERR "Header $hdr: cannot parse: $_;\n";
258             }
259         }
260
261         print STDERR "                                  \r" if $debug;
262
263         next if $reindex;
264
265         # Scan function and reason codes and store them: keep a note of the
266         # maximum code used.
267
268         if ($gotfile) {
269           while(<IN>) {
270                 if(/^\#\s*define\s+(\S+)\s+(\S+)/) {
271                         $name = $1;
272                         $code = $2;
273                         next if $name =~ /^${lib}err/;
274                         unless($name =~ /^${lib}_([RF])_(\w+)$/) {
275                                 print STDERR "Invalid error code $name\n";
276                                 next;
277                         }
278                         if($1 eq "R") {
279                                 $rcodes{$name} = $code;
280                                 if ($rassigned{$lib} =~ /:$code:/) {
281                                         print STDERR "!! ERROR: $lib reason code $code assigned twice (collision at $name)\n";
282                                         ++$errcount;
283                                 }
284                                 $rassigned{$lib} .= "$code:";
285                                 if(!(exists $rextra{$name}) &&
286                                          ($code > $rmax{$lib}) ) {
287                                         $rmax{$lib} = $code;
288                                 }
289                         } else {
290                                 if ($fassigned{$lib} =~ /:$code:/) {
291                                         print STDERR "!! ERROR: $lib function code $code assigned twice (collision at $name)\n";
292                                         ++$errcount;
293                                 }
294                                 $fassigned{$lib} .= "$code:";
295                                 if($code > $fmax{$lib}) {
296                                         $fmax{$lib} = $code;
297                                 }
298                                 $fcodes{$name} = $code;
299                         }
300                 }
301           }
302         }
303
304         if ($debug) {
305                 if (defined($fmax{$lib})) {
306                         print STDERR "Max function code fmax" . "{" . "$lib" . "} = $fmax{$lib}\n";
307                         $fassigned{$lib} =~ m/^:(.*):$/;
308                         @fassigned = sort {$a <=> $b} split(":", $1);
309                         print STDERR "  @fassigned\n";
310                 }
311                 if (defined($rmax{$lib})) {
312                         print STDERR "Max reason code rmax" . "{" . "$lib" . "} = $rmax{$lib}\n";
313                         $rassigned{$lib} =~ m/^:(.*):$/;
314                         @rassigned = sort {$a <=> $b} split(":", $1);
315                         print STDERR "  @rassigned\n";
316                 }
317         }
318
319         if ($lib eq "SSL") {
320                 if ($rmax{$lib} >= 1000) {
321                         print STDERR "!! ERROR: SSL error codes 1000+ are reserved for alerts.\n";
322                         print STDERR "!!        Any new alerts must be added to $config.\n";
323                         ++$errcount;
324                         print STDERR "\n";
325                 }
326         }
327         close IN;
328 }
329
330 # Scan each C source file and look for function and reason codes
331 # This is done by looking for strings that "look like" function or
332 # reason codes: basically anything consisting of all upper case and
333 # numerics which has _F_ or _R_ in it and which has the name of an
334 # error library at the start. This seems to work fine except for the
335 # oddly named structure BIO_F_CTX which needs to be ignored.
336 # If a code doesn't exist in list compiled from headers then mark it
337 # with the value "X" as a place holder to give it a value later.
338 # Store all function and reason codes found in %ufcodes and %urcodes
339 # so all those unreferenced can be printed out.
340
341
342 foreach $file (@source) {
343         # Don't parse the error source file.
344         next if exists $cskip{$file};
345         print STDERR "File loaded: ".$file."\r" if $debug;
346         open(IN, "<$file") || die "Can't open source file $file\n";
347         my $func;
348         my $linenr = 0;
349         while(<IN>) {
350                 # skip obsoleted source files entirely!
351                 last if(/^#error\s+obsolete/);
352                 $linenr++;
353                 if (!/;$/ && /^\**([a-zA-Z_].*[\s*])?([A-Za-z_0-9]+)\(.*([),]|$)/)
354                         {
355                         /^([^()]*(\([^()]*\)[^()]*)*)\(/;
356                         $1 =~ /([A-Za-z_0-9]*)$/;
357                         $func = $1;
358                         }
359
360                 if(/(([A-Z0-9]+)_F_([A-Z0-9_]+))/) {
361                         next unless exists $csrc{$2};
362                         next if($1 eq "BIO_F_BUFFER_CTX");
363                         $ufcodes{$1} = 1;
364                         if(!exists $fcodes{$1}) {
365                                 $fcodes{$1} = "X";
366                                 $fnew{$2}++;
367                         }
368                         $ftrans{$3} = $func unless exists $ftrans{$3};
369             if (uc $func ne $3) {
370                 print STDERR "ERROR: mismatch $file:$linenr $func:$3\n";
371                 $errcount++;
372             }
373                         print STDERR "Function: $1\t= $fcodes{$1} (lib: $2, name: $3)\n" if $debug;
374                 }
375                 if(/(([A-Z0-9]+)_R_[A-Z0-9_]+)/) {
376                         next unless exists $csrc{$2};
377                         $urcodes{$1} = 1;
378                         if(!exists $rcodes{$1}) {
379                                 $rcodes{$1} = "X";
380                                 $rnew{$2}++;
381                         }
382                         print STDERR "Reason: $1\t= $rcodes{$1} (lib: $2)\n" if $debug;
383                 }
384         }
385         close IN;
386 }
387 print STDERR "                                  \n" if $debug;
388
389 # Now process each library in turn.
390
391 foreach $lib (keys %csrc)
392 {
393         my $hfile = $hinc{$lib};
394         my $cfile = $csrc{$lib};
395         if(!$fnew{$lib} && !$rnew{$lib}) {
396                 next unless $rebuild;
397         } else {
398                 print STDERR "$lib:\t\t$fnew{$lib} New Functions,";
399                 print STDERR " $rnew{$lib} New Reasons.\n";
400                 next unless $dowrite;
401         }
402
403         # If we get here then we have some new error codes so we
404         # need to rebuild the header file and C file.
405
406         # Make a sorted list of error and reason codes for later use.
407
408         my @function = sort grep(/^${lib}_/,keys %fcodes);
409         my @reasons = sort grep(/^${lib}_/,keys %rcodes);
410
411         # Rewrite the header file
412
413         $cpp = 0;
414         $cplusplus = 0;
415         if (open(IN, "<$hfile")) {
416             # Copy across the old file
417             while(<IN>) {
418                 $cplusplus = $cpp if /^#.*ifdef.*cplusplus/;
419                 $cpp++ if /^#\s*if/;
420                 $cpp-- if /^#\s*endif/;
421                 push @out, $_;
422                 last if (/BEGIN ERROR CODES/);
423             }
424             close IN;
425         } else {
426             $cpp = 1;
427             $cplusplus = 1;
428             push @out,
429 "/*\n",
430 " * Copyright 1995-$YEAR The OpenSSL Project Authors. All Rights Reserved.\n",
431 " *\n",
432 " * Licensed under the OpenSSL license (the \"License\").  You may not use\n",
433 " * this file except in compliance with the License.  You can obtain a copy\n",
434 " * in the file LICENSE in the source distribution or at\n",
435 " * https://www.openssl.org/source/license.html\n",
436 " */\n",
437 "\n",
438 "#ifndef HEADER_${lib}_ERR_H\n",
439 "# define HEADER_${lib}_ERR_H\n",
440 "\n",
441 "# ifdef  __cplusplus\n",
442 "extern \"C\" {\n",
443 "# endif\n",
444 "\n",
445 "/* BEGIN ERROR CODES */\n";
446         }
447         open (OUT, ">$hfile") || die "Can't Open File $hfile for writing\n";
448
449         print OUT @out;
450         undef @out;
451         print OUT <<"EOF";
452 /*
453  * The following lines are auto generated by the script mkerr.pl. Any changes
454  * made after this point may be overwritten when the script is next run.
455  */
456
457 EOF
458         if($static) {
459                 print OUT <<"EOF";
460 ${staticloader}int ERR_load_${lib}_strings(void);
461
462 EOF
463         } else {
464                 print OUT <<"EOF";
465 ${staticloader}int ERR_load_${lib}_strings(void);
466 ${staticloader}void ERR_unload_${lib}_strings(void);
467 ${staticloader}void ERR_${lib}_error(int function, int reason, char *file, int line);
468 # define ${lib}err(f,r) ERR_${lib}_error((f),(r),OPENSSL_FILE,OPENSSL_LINE)
469
470 EOF
471         }
472         print OUT <<"EOF";
473 /* Error codes for the $lib functions. */
474
475 /* Function codes. */
476 EOF
477
478         foreach $i (@function) {
479                 $z=48 - length($i);
480                 if($fcodes{$i} eq "X") {
481                         $fassigned{$lib} =~ m/^:([^:]*):/;
482                         $findcode = $1;
483                         if (!defined($findcode)) {
484                                 $findcode = $fmax{$lib};
485                         }
486                         while ($fassigned{$lib} =~ m/:$findcode:/) {
487                                 $findcode++;
488                         }
489                         $fcodes{$i} = $findcode;
490                         $fassigned{$lib} .= "$findcode:";
491                         print STDERR "New Function code $i\n" if $debug;
492                 }
493                 printf OUT "# define $i%s $fcodes{$i}\n"," " x $z;
494         }
495
496         print OUT "\n/* Reason codes. */\n";
497
498         foreach $i (@reasons) {
499                 $z=48 - length($i);
500                 if($rcodes{$i} eq "X") {
501                         $rassigned{$lib} =~ m/^:([^:]*):/;
502                         $findcode = $1;
503                         if (!defined($findcode)) {
504                                 $findcode = $rmax{$lib};
505                         }
506                         while ($rassigned{$lib} =~ m/:$findcode:/) {
507                                 $findcode++;
508                         }
509                         $rcodes{$i} = $findcode;
510                         $rassigned{$lib} .= "$findcode:";
511                         print STDERR "New Reason code   $i\n" if $debug;
512                 }
513                 printf OUT "# define $i%s $rcodes{$i}\n"," " x $z;
514         }
515         print OUT <<"EOF";
516
517 EOF
518         do {
519             if ($cplusplus == $cpp) {
520                 print OUT "#", " "x$cpp, "ifdef  __cplusplus\n";
521                 print OUT "}\n";
522                 print OUT "#", " "x$cpp, "endif\n";
523             }
524             if ($cpp-- > 0) {
525                 print OUT "#", " "x$cpp, "endif\n";
526             }
527         } while ($cpp);
528         close OUT;
529
530         # Rewrite the C source file containing the error details.
531
532         # First, read any existing reason string definitions:
533         my %err_reason_strings;
534         if (open(IN,"<$cfile")) {
535                 my $line = "";
536                 while (<IN>) {
537                         s|\R$||; # Better chomp
538                         $_ = $line . $_;
539                         $line = "";
540                         if (/{ERR_(FUNC|REASON)\(/) {
541                                 if (/\b(${lib}_R_\w*)\b.*\"(.*)\"/) {
542                                         $err_reason_strings{$1} = $2;
543                                 } elsif (/\b${lib}_F_(\w*)\b.*\"(.*)\"/) {
544                                         if (!exists $ftrans{$1} && ($1 ne $2)) {
545                                                 print STDERR "WARNING: Mismatched function string $2\n";
546                                                 $ftrans{$1} = $2;
547                                         }
548                                 } else {
549                                         $line = $_;
550                                 }
551                         }
552                 }
553                 close(IN);
554         }
555
556
557         my $hincf;
558         if($static) {
559                 $hincf = $hfile;
560                 $hincf =~ s|.*include/||;
561                 if ($hincf =~ m|^openssl/|) {
562                         $hincf = "<${hincf}>";
563                 } else {
564                         $hincf = "\"${hincf}\"";
565                 }
566         } else {
567                 $hincf = "\"$hfile\"";
568         }
569
570         # If static we know the error code at compile time so use it
571         # in error definitions.
572
573         if ($static)
574                 {
575                 $pack_errcode = "ERR_LIB_${lib}";
576                 $load_errcode = "0";
577                 }
578         else
579                 {
580                 $pack_errcode = "0";
581                 $load_errcode = "ERR_LIB_${lib}";
582                 }
583
584
585         open (OUT,">$cfile") || die "Can't open $cfile for writing";
586
587         print OUT <<"EOF";
588 /*
589  * Generated by util/mkerr.pl DO NOT EDIT
590  * Copyright 1995-$YEAR The OpenSSL Project Authors. All Rights Reserved.
591  *
592  * Licensed under the OpenSSL license (the "License").  You may not use
593  * this file except in compliance with the License.  You can obtain a copy
594  * in the file LICENSE in the source distribution or at
595  * https://www.openssl.org/source/license.html
596  */
597
598 #include <stdio.h>
599 #include <openssl/err.h>
600 #include $hincf
601
602 /* BEGIN ERROR CODES */
603 #ifndef OPENSSL_NO_ERR
604
605 # define ERR_FUNC(func) ERR_PACK($pack_errcode,func,0)
606 # define ERR_REASON(reason) ERR_PACK($pack_errcode,0,reason)
607
608 static ERR_STRING_DATA ${lib}_str_functs[] = {
609 EOF
610         # Add each function code: if a function name is found then use it.
611         foreach $i (@function) {
612                 my $fn;
613                 $i =~ /^${lib}_F_(\S+)$/;
614                 $fn = $1;
615                 if(exists $ftrans{$fn}) {
616                         $fn = $ftrans{$fn};
617                 }
618 #               print OUT "{ERR_PACK($pack_errcode,$i,0),\t\"$fn\"},\n";
619                 if(length($i) + length($fn) > 57) {
620                         print OUT "    {ERR_FUNC($i),\n     \"$fn\"},\n";
621                 } else {
622                         print OUT "    {ERR_FUNC($i), \"$fn\"},\n";
623                 }
624         }
625         print OUT <<"EOF";
626     {0, NULL}
627 };
628
629 static ERR_STRING_DATA ${lib}_str_reasons[] = {
630 EOF
631         # Add each reason code.
632         foreach $i (@reasons) {
633                 my $rn;
634                 my $rstr = "ERR_REASON($i)";
635                 if (exists $err_reason_strings{$i}) {
636                         $rn = $err_reason_strings{$i};
637                 } else {
638                         $i =~ /^${lib}_R_(\S+)$/;
639                         $rn = $1;
640                         $rn =~ tr/_[A-Z]/ [a-z]/;
641                 }
642                 if(length($i) + length($rn) > 55) {
643                         print OUT "    {${rstr},\n     \"$rn\"},\n";
644                 } else {
645                         print OUT "    {${rstr}, \"$rn\"},\n";
646                 }
647         }
648 if($static) {
649         print OUT <<"EOF";
650     {0, NULL}
651 };
652
653 #endif
654
655 ${staticloader}int ERR_load_${lib}_strings(void)
656 {
657 #ifndef OPENSSL_NO_ERR
658
659     if (ERR_func_error_string(${lib}_str_functs[0].error) == NULL) {
660         ERR_load_strings($load_errcode, ${lib}_str_functs);
661         ERR_load_strings($load_errcode, ${lib}_str_reasons);
662     }
663 #endif
664     return 1;
665 }
666 EOF
667 } else {
668         print OUT <<"EOF";
669     {0, NULL}
670 };
671
672 #endif
673
674 #ifdef ${lib}_LIB_NAME
675 static ERR_STRING_DATA ${lib}_lib_name[] = {
676     {0, ${lib}_LIB_NAME},
677     {0, NULL}
678 };
679 #endif
680
681 static int ${lib}_lib_error_code = 0;
682 static int ${lib}_error_init = 1;
683
684 ${staticloader}int ERR_load_${lib}_strings(void)
685 {
686     if (${lib}_lib_error_code == 0)
687         ${lib}_lib_error_code = ERR_get_next_error_library();
688
689     if (${lib}_error_init) {
690         ${lib}_error_init = 0;
691 #ifndef OPENSSL_NO_ERR
692         ERR_load_strings(${lib}_lib_error_code, ${lib}_str_functs);
693         ERR_load_strings(${lib}_lib_error_code, ${lib}_str_reasons);
694 #endif
695
696 #ifdef ${lib}_LIB_NAME
697         ${lib}_lib_name->error = ERR_PACK(${lib}_lib_error_code, 0, 0);
698         ERR_load_strings(0, ${lib}_lib_name);
699 #endif
700     }
701     return 1;
702 }
703
704 ${staticloader}void ERR_unload_${lib}_strings(void)
705 {
706     if (${lib}_error_init == 0) {
707 #ifndef OPENSSL_NO_ERR
708         ERR_unload_strings(${lib}_lib_error_code, ${lib}_str_functs);
709         ERR_unload_strings(${lib}_lib_error_code, ${lib}_str_reasons);
710 #endif
711
712 #ifdef ${lib}_LIB_NAME
713         ERR_unload_strings(0, ${lib}_lib_name);
714 #endif
715         ${lib}_error_init = 1;
716     }
717 }
718
719 ${staticloader}void ERR_${lib}_error(int function, int reason, char *file, int line)
720 {
721     if (${lib}_lib_error_code == 0)
722         ${lib}_lib_error_code = ERR_get_next_error_library();
723     ERR_PUT_error(${lib}_lib_error_code, function, reason, file, line);
724 }
725 EOF
726
727 }
728
729         close OUT;
730         undef %err_reason_strings;
731 }
732
733 if($debug && %notrans) {
734         print STDERR "The following function codes were not translated:\n";
735         foreach(sort keys %notrans)
736         {
737                 print STDERR "$_\n";
738         }
739 }
740
741 # Make a list of unreferenced function and reason codes
742
743 foreach (keys %fcodes) {
744         push (@funref, $_) unless exists $ufcodes{$_};
745 }
746
747 foreach (keys %rcodes) {
748         push (@runref, $_) unless exists $urcodes{$_};
749 }
750
751 if($unref && @funref) {
752         print STDERR "The following function codes were not referenced:\n";
753         foreach(sort @funref)
754         {
755                 print STDERR "$_\n";
756         }
757 }
758
759 if($unref && @runref) {
760         print STDERR "The following reason codes were not referenced:\n";
761         foreach(sort @runref)
762         {
763                 print STDERR "$_\n";
764         }
765 }
766
767 if($errcount) {
768         print STDERR "There were errors, failing...\n\n";
769         exit $errcount;
770 }
771