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