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