230644130b122bb25412fe1f3a6dc83fd5bf8c1b
[openssl.git] / util / mkdef.pl
1 #!/usr/my/bin/perl -w
2 #
3 # generate a .def file
4 #
5 # It does this by parsing the header files and looking for the
6 # prototyped functions: it then prunes the output.
7 #
8
9 $crypto_num="util/libeay.num";
10 $ssl_num=   "util/ssleay.num";
11
12 my $do_update = 0;
13 my $do_crypto = 0;
14 my $do_ssl = 0;
15 $rsaref = 0;
16
17 $W32=1;
18 $NT=0;
19 # Set this to make typesafe STACK definitions appear in DEF
20 $safe_stack_def = 1;
21 foreach (@ARGV)
22         {
23         $W32=1 if $_ eq "32";
24         $W32=0 if $_ eq "16";
25         if($_ eq "NT") {
26                 $W32 = 1;
27                 $NT = 1;
28         }
29         $do_ssl=1 if $_ eq "ssleay";
30         $do_ssl=1 if $_ eq "ssl";
31         $do_crypto=1 if $_ eq "libeay";
32         $do_crypto=1 if $_ eq "crypto";
33         $do_update=1 if $_ eq "update";
34         $rsaref=1 if $_ eq "rsaref";
35         }
36
37 if (!$do_ssl && !$do_crypto)
38         {
39         print STDERR "usage: $0 ( ssl | crypto ) [ 16 | 32 | NT ] [rsaref]\n";
40         exit(1);
41         }
42
43 %ssl_list=&load_numbers($ssl_num);
44 $max_ssl = $max_num;
45 %crypto_list=&load_numbers($crypto_num);
46 $max_crypto = $max_num;
47
48 $ssl="ssl/ssl.h";
49
50 $crypto ="crypto/crypto.h";
51 $crypto.=" crypto/des/des.h";
52 $crypto.=" crypto/idea/idea.h";
53 $crypto.=" crypto/rc4/rc4.h";
54 $crypto.=" crypto/rc5/rc5.h";
55 $crypto.=" crypto/rc2/rc2.h";
56 $crypto.=" crypto/bf/blowfish.h";
57 $crypto.=" crypto/cast/cast.h";
58 $crypto.=" crypto/md2/md2.h";
59 $crypto.=" crypto/md5/md5.h";
60 $crypto.=" crypto/mdc2/mdc2.h";
61 $crypto.=" crypto/sha/sha.h";
62 $crypto.=" crypto/ripemd/ripemd.h";
63
64 $crypto.=" crypto/bn/bn.h";
65 $crypto.=" crypto/rsa/rsa.h";
66 $crypto.=" crypto/dsa/dsa.h";
67 $crypto.=" crypto/dh/dh.h";
68
69 $crypto.=" crypto/stack/stack.h";
70 $crypto.=" crypto/buffer/buffer.h";
71 $crypto.=" crypto/bio/bio.h";
72 $crypto.=" crypto/lhash/lhash.h";
73 $crypto.=" crypto/conf/conf.h";
74 $crypto.=" crypto/txt_db/txt_db.h";
75
76 $crypto.=" crypto/evp/evp.h";
77 $crypto.=" crypto/objects/objects.h";
78 $crypto.=" crypto/pem/pem.h";
79 #$crypto.=" crypto/meth/meth.h";
80 $crypto.=" crypto/asn1/asn1.h";
81 $crypto.=" crypto/asn1/asn1_mac.h";
82 $crypto.=" crypto/err/err.h";
83 $crypto.=" crypto/pkcs7/pkcs7.h";
84 $crypto.=" crypto/pkcs12/pkcs12.h";
85 $crypto.=" crypto/x509/x509.h";
86 $crypto.=" crypto/x509/x509_vfy.h";
87 $crypto.=" crypto/x509v3/x509v3.h";
88 $crypto.=" crypto/rand/rand.h";
89 $crypto.=" crypto/hmac/hmac.h";
90 $crypto.=" crypto/comp/comp.h";
91 $crypto.=" crypto/tmdiff.h";
92
93 @ssl_func = &do_defs("SSLEAY", $ssl);
94 @crypto_func = &do_defs("LIBEAY", $crypto);
95
96
97 if ($do_update) {
98
99 if ($do_ssl == 1) {
100         open(OUT, ">>$ssl_num");
101         &update_numbers(*OUT,"SSLEAY",*ssl_list,$max_ssl, @ssl_func);
102         close OUT;
103 }
104
105 if($do_crypto == 1) {
106         open(OUT, ">>$crypto_num");
107         &update_numbers(*OUT,"LIBEAY",*crypto_list,$max_crypto, @crypto_func);
108         close OUT;
109 }
110
111 } else {
112
113         &print_def_file(*STDOUT,"SSLEAY",*ssl_list,@ssl_func)
114                 if $do_ssl == 1;
115
116         &print_def_file(*STDOUT,"LIBEAY",*crypto_list,@crypto_func)
117                 if $do_crypto == 1;
118
119 }
120
121
122 sub do_defs
123 {
124         my($name,$files)=@_;
125         my @ret;
126         my %funcs;
127
128         foreach $file (split(/\s+/,$files))
129                 {
130                 open(IN,"<$file") || die "unable to open $file:$!\n";
131
132                 my $line = "", $def= "";
133                 my %tag = (
134                         FreeBSD         => 0,
135                         NOPROTO         => 0,
136                         WIN16           => 0,
137                         PERL5           => 0,
138                         _WINDLL         => 0,
139                         NO_FP_API       => 0,
140                         CONST_STRICT    => 0,
141                         TRUE            => 1,
142                 );
143                 while(<IN>) {
144                         last if (/BEGIN ERROR CODES/);
145                         if ($line ne '') {
146                                 $_ = $line . $_;
147                                 $line = '';
148                         }
149
150                         if (/\\$/) {
151                                 $line = $_;
152                                 next;
153                         }
154
155                         $cpp = 1 if /^#.*ifdef.*cplusplus/;
156                         if ($cpp) {
157                                 $cpp = 0 if /^#.*endif/;
158                                 next;
159                         }
160
161                         s/\/\*.*?\*\///gs;                   # ignore comments
162                         s/{[^{}]*}//gs;                      # ignore {} blocks
163                         if (/^\#\s*ifndef (.*)/) {
164                                 push(@tag,$1);
165                                 $tag{$1}=-1;
166                                 next;
167                         } elsif (/^\#\s*if !defined\(([^\)]+)\)/) {
168                                 push(@tag,$1);
169                                 $tag{$1}=-1;
170                                 next;
171                         } elsif (/^\#\s*ifdef (.*)/) {
172                                 push(@tag,$1);
173                                 $tag{$1}=1;
174                                 next;
175                         } elsif (/^\#\s*if defined(.*)/) {
176                                 push(@tag,$1);
177                                 $tag{$1}=1;
178                                 next;
179                         } elsif (/^\#\s*endif/) {
180                                 $tag{$tag[$#tag]}=0;
181                                 pop(@tag);
182                                 next;
183                         } elsif (/^\#\s*else/) {
184                                 my $t=$tag[$#tag];
185                                 $tag{$t}= -$tag{$t};
186                                 next;
187                         } elsif (/^\#\s*if\s+1/) {
188                                 # Dummy tag
189                                 push(@tag,"TRUE");
190                                 $tag{"TRUE"}=1;
191                                 next;
192                         } elsif (/^\#/) {
193                                 next;
194                         }
195                         if ($safe_stack_def &&
196                                 /^\s*DECLARE_STACK_OF\s*\(\s*(\w*)\s*\)/) {
197                                 $funcs{"sk_${1}_new"} = 1;
198                                 $funcs{"sk_${1}_new_null"} = 1;
199                                 $funcs{"sk_${1}_free"} = 1;
200                                 $funcs{"sk_${1}_num"} = 1;
201                                 $funcs{"sk_${1}_value"} = 1;
202                                 $funcs{"sk_${1}_set"} = 1;
203                                 $funcs{"sk_${1}_zero"} = 1;
204                                 $funcs{"sk_${1}_push"} = 1;
205                                 $funcs{"sk_${1}_pop"} = 1;
206                                 $funcs{"sk_${1}_find"} = 1;
207                                 $funcs{"sk_${1}_delete"} = 1;
208                                 $funcs{"sk_${1}_delete_ptr"} = 1;
209                                 $funcs{"sk_${1}_set_cmp_func"} = 1;
210                                 $funcs{"sk_${1}_dup"} = 1;
211                                 $funcs{"sk_${1}_pop_free"} = 1;
212                                 $funcs{"sk_${1}_shift"} = 1;
213                         } elsif ($safe_stack_def &&
214                                 /^\s*DECLARE_ASN1_SET_OF\s*\(\s*(\w*)\s*\)/) {
215                                 $funcs{"d2i_ASN1_SET_OF_${1}"} = 1;
216                                 $funcs{"i2d_ASN1_SET_OF_${1}"} = 1;
217                         } elsif ( 
218                                 ($tag{'FreeBSD'} != 1) &&
219                                 ($tag{'CONST_STRICT'} != 1) &&
220                                 (($W32 && ($tag{'WIN16'} != 1)) ||
221                                  (!$W32 && ($tag{'WIN16'} != -1))) &&
222                                 ($tag{'PERL5'} != 1) &&
223 #                               ($tag{'_WINDLL'} != -1) &&
224                                 ((!$W32 && $tag{'_WINDLL'} != -1) ||
225                                  ($W32 && $tag{'_WINDLL'} != 1)) &&
226                                 ((($tag{'NO_FP_API'} != 1) && $W32) ||
227                                  (($tag{'NO_FP_API'} != -1) && !$W32)))
228                                 {
229                                         if (/{|\/\*/) { # }
230                                                 $line = $_;
231                                         } else {
232                                                 $def .= $_;
233                                         }
234                                 }
235                         }
236                 close(IN);
237
238                 foreach (split /;/, $def) {
239                         s/^[\n\s]*//g;
240                         s/[\n\s]*$//g;
241                         next if(/typedef\W/);
242                         if (/\(\*(\w*)\([^\)]+/) {
243                                 $funcs{$1} = 1;
244                         } elsif (/\w+\W+(\w+)\W*\(\s*\)$/s) {
245                                 # K&R C
246                                 next;
247                         } elsif (/\w+\W+\w+\W*\(.*\)$/s) {
248                                 while (not /\(\)$/s) {
249                                         s/[^\(\)]*\)$/\)/s;
250                                         s/\([^\(\)]*\)\)$/\)/s;
251                                 }
252                                 s/\(void\)//;
253                                 /(\w+)\W*\(\)/s;
254                                 $funcs{$1} = 1;
255                         } elsif (/\(/ and not (/=/)) {
256                                 print STDERR "File $file: cannot parse: $_;\n";
257                         }
258                 }
259         }
260
261         # Prune the returned functions
262
263         delete $funcs{"SSL_add_dir_cert_subjects_to_stack"};
264         delete $funcs{"des_crypt"};
265         delete $funcs{"RSA_PKCS1_RSAref"} unless $rsaref;
266
267         if($W32) {
268                 delete $funcs{"BIO_s_file_internal"};
269                 delete $funcs{"BIO_new_file_internal"};
270                 delete $funcs{"BIO_new_fp_internal"};
271         } else {
272                 if(exists $funcs{"ERR_load_CRYPTO_strings"}) {
273                         delete $funcs{"ERR_load_CRYPTO_strings"};
274                         $funcs{"ERR_load_CRYPTOlib_strings"} = 1;
275                 }
276                 delete $funcs{"BIO_s_file"};
277                 delete $funcs{"BIO_new_file"};
278                 delete $funcs{"BIO_new_fp"};
279         }
280         if (!$NT) {
281                 delete $funcs{"BIO_s_log"};
282         }
283
284         push @ret, keys %funcs;
285
286         return(@ret);
287 }
288
289 sub print_def_file
290 {
291         (*OUT,my $name,*nums,@functions)=@_;
292         my $n =1;
293
294         if ($W32)
295                 { $name.="32"; }
296         else
297                 { $name.="16"; }
298
299         print OUT <<"EOF";
300 ;
301 ; Definition file for the DLL version of the $name library from OpenSSL
302 ;
303
304 LIBRARY         $name
305
306 DESCRIPTION     'OpenSSL $name - http://www.openssl.org/'
307
308 EOF
309
310         if (!$W32) {
311                 print <<"EOF";
312 CODE            PRELOAD MOVEABLE
313 DATA            PRELOAD MOVEABLE SINGLE
314
315 EXETYPE         WINDOWS
316
317 HEAPSIZE        4096
318 STACKSIZE       8192
319
320 EOF
321         }
322
323         print "EXPORTS\n";
324
325
326         (@e)=grep(/^SSLeay/,@functions);
327         (@r)=grep(!/^SSLeay/,@functions);
328         @functions=((sort @e),(sort @r));
329
330         foreach $func (@functions) {
331                 if (!defined($nums{$func})) {
332                         printf STDERR "$func does not have a number assigned\n"
333                                         if(!$do_update);
334                 } else {
335                         $n=$nums{$func};
336                         printf OUT "    %s%-40s@%d\n",($W32)?"":"_",$func,$n;
337                 }
338         }
339         printf OUT "\n";
340 }
341
342 sub load_numbers
343 {
344         my($name)=@_;
345         my(@a,%ret);
346
347         $max_num = 0;
348
349         open(IN,"<$name") || die "unable to open $name:$!\n";
350         while (<IN>) {
351                 chop;
352                 s/#.*$//;
353                 next if /^\s*$/;
354                 @a=split;
355                 $ret{$a[0]}=$a[1];
356                 $max_num = $a[1] if $a[1] > $max_num;
357         }
358         close(IN);
359         return(%ret);
360 }
361
362 sub update_numbers
363 {
364         (*OUT,$name,*nums,my $start_num, my @functions)=@_;
365         my $new_funcs = 0;
366         print STDERR "Updating $name\n";
367         foreach $func (@functions) {
368                 if (!exists $nums{$func}) {
369                         $new_funcs++;
370                         printf OUT "%s%-40s%d\n","",$func, ++$start_num;
371                 }
372         }
373         if($new_funcs) {
374                 print STDERR "$new_funcs New Functions added\n";
375         } else {
376                 print STDERR "No New Functions Added\n";
377         }
378 }