Change the command line options of mkerr.pl so -static is now default and
[openssl.git] / util / mkerr.pl
1 #!/usr/local/bin/perl -w
2
3 my $config = "crypto/err/openssl.ec";
4 my $debug = 0;
5 my $rebuild = 0;
6 my $static = 1;
7 my $recurse = 0;
8 my $reindex = 0;
9 my $dowrite = 0;
10
11
12 while (@ARGV) {
13         my $arg = $ARGV[0];
14         if($arg eq "-conf") {
15                 shift @ARGV;
16                 $config = shift @ARGV;
17         } elsif($arg eq "-debug") {
18                 $debug = 1;
19                 shift @ARGV;
20         } elsif($arg eq "-rebuild") {
21                 $rebuild = 1;
22                 shift @ARGV;
23         } elsif($arg eq "-recurse") {
24                 $recurse = 1;
25                 shift @ARGV;
26         } elsif($arg eq "-reindex") {
27                 $reindex = 1;
28                 shift @ARGV;
29         } elsif($arg eq "-nostatic") {
30                 $static = 0;
31                 shift @ARGV;
32         } elsif($arg eq "-write") {
33                 $dowrite = 1;
34                 shift @ARGV;
35         } else {
36                 last;
37         }
38 }
39
40 if($recurse) {
41         @source = (<crypto/*.c>, <crypto/*/*.c>, ,<rsaref/*.c>, <ssl/*.c>);
42 } else {
43         @source = @ARGV;
44 }
45
46 # Read in the config file
47
48 open(IN, "<$config") || die "Can't open config file $config";
49
50 # Parse config file
51
52 while(<IN>)
53 {
54         if(/^L\s+(\S+)\s+(\S+)\s+(\S+)/) {
55                 $hinc{$1} = $2;
56                 $cskip{$3} = $1;
57                 if($3 ne "NONE") {
58                         $csrc{$1} = $3;
59                         $fmax{$1} = 99;
60                         $rmax{$1} = 99;
61                         $fnew{$1} = 0;
62                         $rnew{$1} = 0;
63                 }
64         } elsif (/^F\s+(\S+)/) {
65         # Add extra function with $1
66         } elsif (/^R\s+(\S+)\s+(\S+)/) {
67                 $rextra{$1} = $2;
68                 $rcodes{$1} = $2;
69         # Add extra reason with $1, value $2
70         }
71 }
72
73 close IN;
74
75 # Scan each header file in turn and make a list of error codes
76 # and function names
77
78 while (($lib, $hdr) = each %hinc)
79 {
80         next if($hdr eq "NONE");
81         print STDERR "Scanning header file $hdr\n" if $debug; 
82         open(IN, "<$hdr") || die "Can't open Header file $hdr\n";
83         my $line = "", $def= "";
84         while(<IN>) {
85             last if(/BEGIN\s+ERROR\s+CODES/);
86             if ($line ne '') {
87                 $_ = $line . $_;
88                 $line = '';
89             }
90
91             if (/\\$/) {
92                 $line = $_;
93                 next;
94             }
95
96             $cpp = 1 if /^#.*ifdef.*cplusplus/;  # skip "C" declaration
97             if ($cpp) {
98                 $cpp = 0 if /^#.*endif/;
99                 next;
100             }
101
102             next if (/^#/);                      # skip preprocessor directives
103
104             s/\/\*.*?\*\///gs;                   # ignore comments
105             s/{[^{}]*}//gs;                      # ignore {} blocks
106
107             if (/{|\/\*/) { # Add a } so editor works...
108                 $line = $_;
109             } else {
110                 $def .= $_;
111             }
112         }
113
114         foreach (split /;/, $def) {
115             s/^[\n\s]*//g;
116             s/[\n\s]*$//g;
117             next if (/\w+\W+(\w+)\W*\(\s*\)$/s); # K&R C
118             next if (/\(\*(\w*)\([^\)]+/);
119             if (/\w+\W+\w+\W*\(.*\)$/s) {
120                 while (not /\(\)$/s) {
121                     s/[^\(\)]*\)$/\)/s;
122                     s/\([^\(\)]*\)\)$/\)/s;
123                 }
124                 s/\(void\)//;
125                 /(\w+)\W*\(\)/s;
126                 next if(/typedef\W/);
127                 my $name = $1;
128                 $name =~ tr/[a-z]/[A-Z]/;
129                 $ftrans{$name} = $1;
130                 
131             } elsif (/\(/ and not (/=/ or /DECLARE_STACK/)) {
132                 print STDERR "Header $hdr: cannot parse: $_;\n";
133             }
134         }
135
136         next if $reindex;
137
138         # Scan function and reason codes and store them: keep a note of the
139         # maximum code used.
140
141         while(<IN>) {
142                 if(/^#define\s+(\S+)\s+(\S+)/) {
143                         $name = $1;
144                         $code = $2;
145                         unless($name =~ /^${lib}_([RF])_(\w+)$/) {
146                                 print STDERR "Invalid error code $name\n";
147                                 next;
148                         }
149                         if($1 eq "R") {
150                                 $rcodes{$name} = $code;
151                                 if(!(exists $rextra{$name}) &&
152                                          ($code > $rmax{$lib}) ) {
153                                         $rmax{$lib} = $code;
154                                 }
155                         } else {
156                                 if($code > $fmax{$lib}) {
157                                         $fmax{$lib} = $code;
158                                 }
159                                 $fcodes{$name} = $code;
160                         }
161                 }
162         }
163         close IN;
164 }
165
166 # Scan each C source file and look for function and reason codes
167 # This is done by looking for strings that "look like" function or
168 # reason codes: basically anything consisting of all upper case and
169 # numerics which has _F_ or _R_ in it and which has the name of an
170 # error library at the start. This seems to work fine except for the
171 # oddly named structure BIO_F_CTX which needs to be ignored.
172 # If a code doesn't exist in list compiled from headers then mark it
173 # with the value "X" as a place holder to give it a value later.
174 # Store all function and reason codes found in %ufcodes and %urcodes
175 # so all those unreferenced can be printed out.
176
177
178 foreach $file (@source) {
179         # Don't parse the error source file.
180         next if exists $cskip{$file};
181         open(IN, "<$file") || die "Can't open source file $file\n";
182         while(<IN>) {
183                 if(/(([A-Z0-9]+)_F_([A-Z0-9_]+))/) {
184                         next unless exists $csrc{$2};
185                         next if($1 eq "BIO_F_BUFFER_CTX");
186                         $ufcodes{$1} = 1;
187                         if(!exists $fcodes{$1}) {
188                                 $fcodes{$1} = "X";
189                                 $fnew{$2}++;
190                         }
191                         $notrans{$1} = 1 unless exists $ftrans{$3};
192                 }
193                 if(/(([A-Z0-9]+)_R_[A-Z0-9_]+)/) {
194                         next unless exists $csrc{$2};
195                         $urcodes{$1} = 1;
196                         if(!exists $rcodes{$1}) {
197                                 $rcodes{$1} = "X";
198                                 $rnew{$2}++;
199                         }
200                 } 
201         }
202         close IN;
203 }
204
205 # Now process each library in turn.
206
207 foreach $lib (keys %csrc)
208 {
209         my $hfile = $hinc{$lib};
210         my $cfile = $csrc{$lib};
211         if(!$fnew{$lib} && !$rnew{$lib}) {
212                 print STDERR "$lib:\t\tNo new error codes\n";
213                 next unless $rebuild;
214         } else {
215                 print STDERR "$lib:\t\t$fnew{$lib} New Functions,";
216                 print STDERR " $rnew{$lib} New Reasons.\n";
217                 next unless $dowrite;
218         }
219
220         # If we get here then we have some new error codes so we
221         # need to rebuild the header file and C file.
222
223         # Make a sorted list of error and reason codes for later use.
224
225         my @function = sort grep(/^${lib}_/,keys %fcodes);
226         my @reasons = sort grep(/^${lib}_/,keys %rcodes);
227
228         # Rewrite the header file
229
230         open(IN, "<$hfile") || die "Can't Open Header File $hfile\n";
231
232         # Copy across the old file
233         while(<IN>) {
234                 push @out, $_;
235                 last if (/BEGIN ERROR CODES/);
236         }
237         close IN;
238
239         open (OUT, ">$hfile") || die "Can't Open File $hfile for writing\n";
240
241         print OUT @out;
242         undef @out;
243         print OUT <<"EOF";
244 /* The following lines are auto generated by the script mkerr.pl. Any changes
245  * made after this point may be overwritten when the script is next run.
246  */
247
248 /* Error codes for the $lib functions. */
249
250 /* Function codes. */
251 EOF
252
253         foreach $i (@function) {
254                 $z=6-int(length($i)/8);
255                 if($fcodes{$i} eq "X") {
256                         $fcodes{$i} = ++$fmax{$lib};
257                         print STDERR "New Function code $i\n" if $debug;
258                 }
259                 printf OUT "#define $i%s $fcodes{$i}\n","\t" x $z;
260         }
261
262         print OUT "\n/* Reason codes. */\n";
263
264         foreach $i (@reasons) {
265                 $z=6-int(length($i)/8);
266                 if($rcodes{$i} eq "X") {
267                         $rcodes{$i} = ++$rmax{$lib};
268                         print STDERR "New Reason code   $i\n" if $debug;
269                 }
270                 printf OUT "#define $i%s $rcodes{$i}\n","\t" x $z;
271         }
272         print OUT <<"EOF";
273
274 #ifdef  __cplusplus
275 }
276 #endif
277 #endif
278
279 EOF
280         close OUT;
281
282         # Rewrite the C source file containing the error details.
283
284         $hfile =~ /([^\/]+)$/;
285         my $hincf = $1;
286
287         open (OUT,">$cfile") || die "Can't open $cfile for writing";
288
289         print OUT <<"EOF";
290 /* $cfile */
291 /* ====================================================================
292  * Copyright (c) 1999 The OpenSSL Project.  All rights reserved.
293  *
294  * Redistribution and use in source and binary forms, with or without
295  * modification, are permitted provided that the following conditions
296  * are met:
297  *
298  * 1. Redistributions of source code must retain the above copyright
299  *    notice, this list of conditions and the following disclaimer. 
300  *
301  * 2. Redistributions in binary form must reproduce the above copyright
302  *    notice, this list of conditions and the following disclaimer in
303  *    the documentation and/or other materials provided with the
304  *    distribution.
305  *
306  * 3. All advertising materials mentioning features or use of this
307  *    software must display the following acknowledgment:
308  *    "This product includes software developed by the OpenSSL Project
309  *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
310  *
311  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
312  *    endorse or promote products derived from this software without
313  *    prior written permission. For written permission, please contact
314  *    openssl-core\@OpenSSL.org.
315  *
316  * 5. Products derived from this software may not be called "OpenSSL"
317  *    nor may "OpenSSL" appear in their names without prior written
318  *    permission of the OpenSSL Project.
319  *
320  * 6. Redistributions of any form whatsoever must retain the following
321  *    acknowledgment:
322  *    "This product includes software developed by the OpenSSL Project
323  *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
324  *
325  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
326  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
327  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
328  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
329  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
330  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
331  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
332  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
333  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
334  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
335  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
336  * OF THE POSSIBILITY OF SUCH DAMAGE.
337  * ====================================================================
338  *
339  * This product includes cryptographic software written by Eric Young
340  * (eay\@cryptsoft.com).  This product includes software written by Tim
341  * Hudson (tjh\@cryptsoft.com).
342  *
343  */
344
345 /* NOTE: this file was auto generated by the mkerr.pl script: any changes
346  * made to it will be overwritten when the script next updates this file.
347  */
348
349 #include <stdio.h>
350 #include <openssl/err.h>
351 #include <openssl/$hincf>
352
353 /* BEGIN ERROR CODES */
354 #ifndef NO_ERR
355 static ERR_STRING_DATA ${lib}_str_functs[]=
356         {
357 EOF
358         # Add each function code: if a function name is found then use it.
359         foreach $i (@function) {
360                 my $fn;
361                 $i =~ /^${lib}_F_(\S+)$/;
362                 $fn = $1;
363                 if(exists $ftrans{$fn}) {
364                         $fn = $ftrans{$fn};
365                 }
366                 print OUT "{ERR_PACK(0,$i,0),\t\"$fn\"},\n";
367         }
368         print OUT <<"EOF";
369 {0,NULL}
370         };
371
372 static ERR_STRING_DATA ${lib}_str_reasons[]=
373         {
374 EOF
375         # Add each reason code.
376         foreach $i (@reasons) {
377                 my $rn;
378                 my $nspc = 0;
379                 $i =~ /^${lib}_R_(\S+)$/;
380                 $rn = $1;
381                 $rn =~ tr/_[A-Z]/ [a-z]/;
382                 $nspc = 40 - length($i) unless length($i) > 40;
383                 $nspc = " " x $nspc;
384                 print OUT "{${i}${nspc},\"$rn\"},\n";
385         }
386 if($static) {
387         print OUT <<"EOF";
388 {0,NULL}
389         };
390
391 #endif
392
393 void ERR_load_${lib}_strings(void)
394         {
395         static int init=1;
396
397         if (init)
398                 {
399                 init=0;
400 #ifndef NO_ERR
401                 ERR_load_strings(ERR_LIB_${lib},${lib}_str_functs);
402                 ERR_load_strings(ERR_LIB_${lib},${lib}_str_reasons);
403 #endif
404
405                 }
406         }
407 EOF
408 } else {
409         print OUT <<"EOF";
410 {0,NULL}
411         };
412
413 #endif
414
415 #ifdef ${lib}_LIB_NAME
416 static ERR_STRING_DATA ${lib}_lib_name[]=
417         {
418 {0      ,${lib}_LIB_NAME},
419 {0,NULL}
420         };
421 #endif
422
423
424 int ${lib}_lib_error_code=0;
425
426 void ERR_load_${lib}_strings(void)
427         {
428         static int init=1;
429
430         if (${lib}_lib_error_code == 0)
431                 ${lib}_lib_error_code=ERR_get_next_error_library();
432
433         if (init)
434                 {
435                 init=0;
436 #ifndef NO_ERR
437                 ERR_load_strings(${lib}_lib_error_code,${lib}_str_functs);
438                 ERR_load_strings(${lib}_lib_error_code,${lib}_str_reasons);
439 #endif
440
441 #ifdef ${lib}_LIB_NAME
442                 ${lib}_lib_name->error = ERR_PACK(${lib}_lib_error_code,0,0);
443                 ERR_load_strings(0,${lib}_lib_name);
444 #endif;
445                 }
446         }
447
448 void ERR_${lib}_error(int function, int reason, char *file, int line)
449         {
450         if (${lib}_lib_error_code == 0)
451                 ${lib}_lib_error_code=ERR_get_next_error_library();
452         ERR_PUT_error(${lib}_lib_error_code,function,reason,file,line);
453         }
454 EOF
455
456 }
457
458         close OUT;
459
460 }
461
462 if($debug && defined(%notrans)) {
463         print STDERR "The following function codes were not translated:\n";
464         foreach(sort keys %notrans)
465         {
466                 print STDERR "$_\n";
467         }
468 }
469
470 # Make a list of unreferenced function and reason codes
471
472 foreach (keys %fcodes) {
473         push (@funref, $_) unless exists $ufcodes{$_};
474 }
475
476 foreach (keys %rcodes) {
477         push (@runref, $_) unless exists $urcodes{$_};
478 }
479
480 if($debug && defined(@funref) ) {
481         print STDERR "The following function codes were not referenced:\n";
482         foreach(sort @funref)
483         {
484                 print STDERR "$_\n";
485         }
486 }
487
488 if($debug && defined(@runref) ) {
489         print STDERR "The following reason codes were not referenced:\n";
490         foreach(sort @runref)
491         {
492                 print STDERR "$_\n";
493         }
494 }