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