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