xref: /freebsd/crypto/openssl/util/mkdef.pl (revision 6780ab54325a71e7e70112b11657973edde8655e)
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# Intermediary files are created, call libeay.num and ssleay.num,...
9# Previously, they had the following format:
10#
11#	routine-name	nnnn
12#
13# But that isn't enough for a number of reasons, the first on being that
14# this format is (needlessly) very Win32-centric, and even then...
15# One of the biggest problems is that there's no information about what
16# routines should actually be used, which varies with what crypto algorithms
17# are disabled.  Also, some operating systems (for example VMS with VAX C)
18# need to keep track of the global variables as well as the functions.
19#
20# So, a remake of this script is done so as to include information on the
21# kind of symbol it is (function or variable) and what algorithms they're
22# part of.  This will allow easy translating to .def files or the corresponding
23# file in other operating systems (a .opt file for VMS, possibly with a .mar
24# file).
25#
26# The format now becomes:
27#
28#	routine-name	nnnn	info
29#
30# and the "info" part is actually a colon-separated string of fields with
31# the following meaning:
32#
33#	existence:platform:kind:algorithms
34#
35# - "existence" can be "EXIST" or "NOEXIST" depending on if the symbol is
36#   found somewhere in the source,
37# - "platforms" is empty if it exists on all platforms, otherwise it contains
38#   comma-separated list of the platform, just as they are if the symbol exists
39#   for those platforms, or prepended with a "!" if not.  This helps resolve
40#   symbol name variants for platforms where the names are too long for the
41#   compiler or linker, or if the systems is case insensitive and there is a
42#   clash, or the symbol is implemented differently (see
43#   EXPORT_VAR_AS_FUNCTION).  This script assumes renaming of symbols is found
44#   in the file crypto/symhacks.h.
45#   The semantics for the platforms is that every item is checked against the
46#   environment.  For the negative items ("!FOO"), if any of them is false
47#   (i.e. "FOO" is true) in the environment, the corresponding symbol can't be
48#   used.  For the positive itms, if all of them are false in the environment,
49#   the corresponding symbol can't be used.  Any combination of positive and
50#   negative items are possible, and of course leave room for some redundancy.
51# - "kind" is "FUNCTION" or "VARIABLE".  The meaning of that is obvious.
52# - "algorithms" is a comma-separated list of algorithm names.  This helps
53#   exclude symbols that are part of an algorithm that some user wants to
54#   exclude.
55#
56
57my $debug=0;
58
59my $crypto_num= "util/libeay.num";
60my $ssl_num=    "util/ssleay.num";
61my $libname;
62
63my $do_update = 0;
64my $do_rewrite = 1;
65my $do_crypto = 0;
66my $do_ssl = 0;
67my $do_ctest = 0;
68my $do_ctestall = 0;
69my $do_checkexist = 0;
70
71my $VMSVAX=0;
72my $VMSAlpha=0;
73my $VMS=0;
74my $W32=0;
75my $W16=0;
76my $NT=0;
77my $OS2=0;
78# Set this to make typesafe STACK definitions appear in DEF
79my $safe_stack_def = 0;
80
81my @known_platforms = ( "__FreeBSD__", "PERL5", "NeXT",
82			"EXPORT_VAR_AS_FUNCTION" );
83my @known_ossl_platforms = ( "VMS", "WIN16", "WIN32", "WINNT", "OS2" );
84my @known_algorithms = ( "RC2", "RC4", "RC5", "IDEA", "DES", "BF",
85			 "CAST", "MD2", "MD4", "MD5", "SHA", "SHA0", "SHA1",
86			 "RIPEMD",
87			 "MDC2", "RSA", "DSA", "DH", "EC", "HMAC", "AES",
88			 # Envelope "algorithms"
89			 "EVP", "X509", "ASN1_TYPEDEFS",
90			 # Helper "algorithms"
91			 "BIO", "COMP", "BUFFER", "LHASH", "STACK", "ERR",
92			 "LOCKING",
93			 # External "algorithms"
94			 "FP_API", "STDIO", "SOCK", "KRB5" );
95
96my $options="";
97open(IN,"<Makefile.ssl") || die "unable to open Makefile.ssl!\n";
98while(<IN>) {
99    $options=$1 if (/^OPTIONS=(.*)$/);
100}
101close(IN);
102
103# The following ciphers may be excluded (by Configure). This means functions
104# defined with ifndef(NO_XXX) are not included in the .def file, and everything
105# in directory xxx is ignored.
106my $no_rc2; my $no_rc4; my $no_rc5; my $no_idea; my $no_des; my $no_bf;
107my $no_cast;
108my $no_md2; my $no_md4; my $no_md5; my $no_sha; my $no_ripemd; my $no_mdc2;
109my $no_rsa; my $no_dsa; my $no_dh; my $no_hmac=0; my $no_aes; my $no_krb5;
110my $no_ec;
111my $no_fp_api;
112
113foreach (@ARGV, split(/ /, $options))
114	{
115	$debug=1 if $_ eq "debug";
116	$W32=1 if $_ eq "32";
117	$W16=1 if $_ eq "16";
118	if($_ eq "NT") {
119		$W32 = 1;
120		$NT = 1;
121	}
122	if ($_ eq "VMS-VAX") {
123		$VMS=1;
124		$VMSVAX=1;
125	}
126	if ($_ eq "VMS-Alpha") {
127		$VMS=1;
128		$VMSAlpha=1;
129	}
130	$VMS=1 if $_ eq "VMS";
131	$OS2=1 if $_ eq "OS2";
132
133	$do_ssl=1 if $_ eq "ssleay";
134	if ($_ eq "ssl") {
135		$do_ssl=1;
136		$libname=$_
137	}
138	$do_crypto=1 if $_ eq "libeay";
139	if ($_ eq "crypto") {
140		$do_crypto=1;
141		$libname=$_;
142	}
143	$do_update=1 if $_ eq "update";
144	$do_rewrite=1 if $_ eq "rewrite";
145	$do_ctest=1 if $_ eq "ctest";
146	$do_ctestall=1 if $_ eq "ctestall";
147	$do_checkexist=1 if $_ eq "exist";
148	#$safe_stack_def=1 if $_ eq "-DDEBUG_SAFESTACK";
149
150	if    (/^no-rc2$/)      { $no_rc2=1; }
151	elsif (/^no-rc4$/)      { $no_rc4=1; }
152	elsif (/^no-rc5$/)      { $no_rc5=1; }
153	elsif (/^no-idea$/)     { $no_idea=1; }
154	elsif (/^no-des$/)      { $no_des=1; $no_mdc2=1; }
155	elsif (/^no-bf$/)       { $no_bf=1; }
156	elsif (/^no-cast$/)     { $no_cast=1; }
157	elsif (/^no-md2$/)      { $no_md2=1; }
158	elsif (/^no-md4$/)      { $no_md4=1; }
159	elsif (/^no-md5$/)      { $no_md5=1; }
160	elsif (/^no-sha$/)      { $no_sha=1; }
161	elsif (/^no-ripemd$/)   { $no_ripemd=1; }
162	elsif (/^no-mdc2$/)     { $no_mdc2=1; }
163	elsif (/^no-rsa$/)      { $no_rsa=1; }
164	elsif (/^no-dsa$/)      { $no_dsa=1; }
165	elsif (/^no-dh$/)       { $no_dh=1; }
166	elsif (/^no-ec$/)       { $no_ec=1; }
167	elsif (/^no-hmac$/)	{ $no_hmac=1; }
168	elsif (/^no-aes$/)	{ $no_aes=1; }
169	elsif (/^no-evp$/)	{ $no_evp=1; }
170	elsif (/^no-lhash$/)	{ $no_lhash=1; }
171	elsif (/^no-stack$/)	{ $no_stack=1; }
172	elsif (/^no-err$/)	{ $no_err=1; }
173	elsif (/^no-buffer$/)	{ $no_buffer=1; }
174	elsif (/^no-bio$/)	{ $no_bio=1; }
175	#elsif (/^no-locking$/)	{ $no_locking=1; }
176	elsif (/^no-comp$/)	{ $no_comp=1; }
177	elsif (/^no-dso$/)	{ $no_dso=1; }
178	elsif (/^no-krb5$/)	{ $no_krb5=1; }
179	}
180
181
182if (!$libname) {
183	if ($do_ssl) {
184		$libname="SSLEAY";
185	}
186	if ($do_crypto) {
187		$libname="LIBEAY";
188	}
189}
190
191# If no platform is given, assume WIN32
192if ($W32 + $W16 + $VMS + $OS2 == 0) {
193	$W32 = 1;
194}
195
196# Add extra knowledge
197if ($W16) {
198	$no_fp_api=1;
199}
200
201if (!$do_ssl && !$do_crypto)
202	{
203	print STDERR "usage: $0 ( ssl | crypto ) [ 16 | 32 | NT | OS2 ]\n";
204	exit(1);
205	}
206
207%ssl_list=&load_numbers($ssl_num);
208$max_ssl = $max_num;
209%crypto_list=&load_numbers($crypto_num);
210$max_crypto = $max_num;
211
212my $ssl="ssl/ssl.h";
213$ssl.=" ssl/kssl.h";
214
215my $crypto ="crypto/crypto.h";
216$crypto.=" crypto/des/des.h crypto/des/des_old.h" ; # unless $no_des;
217$crypto.=" crypto/idea/idea.h" ; # unless $no_idea;
218$crypto.=" crypto/rc4/rc4.h" ; # unless $no_rc4;
219$crypto.=" crypto/rc5/rc5.h" ; # unless $no_rc5;
220$crypto.=" crypto/rc2/rc2.h" ; # unless $no_rc2;
221$crypto.=" crypto/bf/blowfish.h" ; # unless $no_bf;
222$crypto.=" crypto/cast/cast.h" ; # unless $no_cast;
223$crypto.=" crypto/md2/md2.h" ; # unless $no_md2;
224$crypto.=" crypto/md4/md4.h" ; # unless $no_md4;
225$crypto.=" crypto/md5/md5.h" ; # unless $no_md5;
226$crypto.=" crypto/mdc2/mdc2.h" ; # unless $no_mdc2;
227$crypto.=" crypto/sha/sha.h" ; # unless $no_sha;
228$crypto.=" crypto/ripemd/ripemd.h" ; # unless $no_ripemd;
229$crypto.=" crypto/aes/aes.h" ; # unless $no_aes;
230
231$crypto.=" crypto/bn/bn.h";
232$crypto.=" crypto/rsa/rsa.h" ; # unless $no_rsa;
233$crypto.=" crypto/dsa/dsa.h" ; # unless $no_dsa;
234$crypto.=" crypto/dh/dh.h" ; # unless $no_dh;
235$crypto.=" crypto/ec/ec.h" ; # unless $no_ec;
236$crypto.=" crypto/hmac/hmac.h" ; # unless $no_hmac;
237
238$crypto.=" crypto/engine/engine.h";
239$crypto.=" crypto/stack/stack.h" ; # unless $no_stack;
240$crypto.=" crypto/buffer/buffer.h" ; # unless $no_buffer;
241$crypto.=" crypto/bio/bio.h" ; # unless $no_bio;
242$crypto.=" crypto/dso/dso.h" ; # unless $no_dso;
243$crypto.=" crypto/lhash/lhash.h" ; # unless $no_lhash;
244$crypto.=" crypto/conf/conf.h";
245$crypto.=" crypto/txt_db/txt_db.h";
246
247$crypto.=" crypto/evp/evp.h" ; # unless $no_evp;
248$crypto.=" crypto/objects/objects.h";
249$crypto.=" crypto/pem/pem.h";
250#$crypto.=" crypto/meth/meth.h";
251$crypto.=" crypto/asn1/asn1.h";
252$crypto.=" crypto/asn1/asn1t.h";
253$crypto.=" crypto/asn1/asn1_mac.h";
254$crypto.=" crypto/err/err.h" ; # unless $no_err;
255$crypto.=" crypto/pkcs7/pkcs7.h";
256$crypto.=" crypto/pkcs12/pkcs12.h";
257$crypto.=" crypto/x509/x509.h";
258$crypto.=" crypto/x509/x509_vfy.h";
259$crypto.=" crypto/x509v3/x509v3.h";
260$crypto.=" crypto/rand/rand.h";
261$crypto.=" crypto/comp/comp.h" ; # unless $no_comp;
262$crypto.=" crypto/ocsp/ocsp.h";
263$crypto.=" crypto/ui/ui.h crypto/ui/ui_compat.h";
264$crypto.=" crypto/krb5/krb5_asn.h";
265$crypto.=" crypto/tmdiff.h";
266
267my $symhacks="crypto/symhacks.h";
268
269my @ssl_symbols = &do_defs("SSLEAY", $ssl, $symhacks);
270my @crypto_symbols = &do_defs("LIBEAY", $crypto, $symhacks);
271
272if ($do_update) {
273
274if ($do_ssl == 1) {
275
276	&maybe_add_info("SSLEAY",*ssl_list,@ssl_symbols);
277	if ($do_rewrite == 1) {
278		open(OUT, ">$ssl_num");
279		&rewrite_numbers(*OUT,"SSLEAY",*ssl_list,@ssl_symbols);
280	} else {
281		open(OUT, ">>$ssl_num");
282	}
283	&update_numbers(*OUT,"SSLEAY",*ssl_list,$max_ssl,@ssl_symbols);
284	close OUT;
285}
286
287if($do_crypto == 1) {
288
289	&maybe_add_info("LIBEAY",*crypto_list,@crypto_symbols);
290	if ($do_rewrite == 1) {
291		open(OUT, ">$crypto_num");
292		&rewrite_numbers(*OUT,"LIBEAY",*crypto_list,@crypto_symbols);
293	} else {
294		open(OUT, ">>$crypto_num");
295	}
296	&update_numbers(*OUT,"LIBEAY",*crypto_list,$max_crypto,@crypto_symbols);
297	close OUT;
298}
299
300} elsif ($do_checkexist) {
301	&check_existing(*ssl_list, @ssl_symbols)
302		if $do_ssl == 1;
303	&check_existing(*crypto_list, @crypto_symbols)
304		if $do_crypto == 1;
305} elsif ($do_ctest || $do_ctestall) {
306
307	print <<"EOF";
308
309/* Test file to check all DEF file symbols are present by trying
310 * to link to all of them. This is *not* intended to be run!
311 */
312
313int main()
314{
315EOF
316	&print_test_file(*STDOUT,"SSLEAY",*ssl_list,$do_ctestall,@ssl_symbols)
317		if $do_ssl == 1;
318
319	&print_test_file(*STDOUT,"LIBEAY",*crypto_list,$do_ctestall,@crypto_symbols)
320		if $do_crypto == 1;
321
322	print "}\n";
323
324} else {
325
326	&print_def_file(*STDOUT,$libname,*ssl_list,@ssl_symbols)
327		if $do_ssl == 1;
328
329	&print_def_file(*STDOUT,$libname,*crypto_list,@crypto_symbols)
330		if $do_crypto == 1;
331
332}
333
334
335sub do_defs
336{
337	my($name,$files,$symhacksfile)=@_;
338	my $file;
339	my @ret;
340	my %syms;
341	my %platform;		# For anything undefined, we assume ""
342	my %kind;		# For anything undefined, we assume "FUNCTION"
343	my %algorithm;		# For anything undefined, we assume ""
344	my %variant;
345	my %variant_cnt;	# To be able to allocate "name{n}" if "name"
346				# is the same name as the original.
347	my $cpp;
348	my %unknown_algorithms = ();
349
350	foreach $file (split(/\s+/,$symhacksfile." ".$files))
351		{
352		print STDERR "DEBUG: starting on $file:\n" if $debug;
353		open(IN,"<$file") || die "unable to open $file:$!\n";
354		my $line = "", my $def= "";
355		my %tag = (
356			(map { $_ => 0 } @known_platforms),
357			(map { "OPENSSL_SYS_".$_ => 0 } @known_ossl_platforms),
358			(map { "OPENSSL_NO_".$_ => 0 } @known_algorithms),
359			NOPROTO		=> 0,
360			PERL5		=> 0,
361			_WINDLL		=> 0,
362			CONST_STRICT	=> 0,
363			TRUE		=> 1,
364		);
365		my $symhacking = $file eq $symhacksfile;
366		my @current_platforms = ();
367		my @current_algorithms = ();
368
369		# params: symbol, alias, platforms, kind
370		# The reason to put this subroutine in a variable is that
371		# it will otherwise create it's own, unshared, version of
372		# %tag and %variant...
373		my $make_variant = sub
374		{
375			my ($s, $a, $p, $k) = @_;
376			my ($a1, $a2);
377
378			print STDERR "DEBUG: make_variant: Entered with ",$s,", ",$a,", ",(defined($p)?$p:""),", ",(defined($k)?$k:""),"\n" if $debug;
379			if (defined($p))
380			{
381				$a1 = join(",",$p,
382					   grep(!/^$/,
383						map { $tag{$_} == 1 ? $_ : "" }
384						@known_platforms));
385			}
386			else
387			{
388				$a1 = join(",",
389					   grep(!/^$/,
390						map { $tag{$_} == 1 ? $_ : "" }
391						@known_platforms));
392			}
393			$a2 = join(",",
394				   grep(!/^$/,
395					map { $tag{"OPENSSL_SYS_".$_} == 1 ? $_ : "" }
396					@known_ossl_platforms));
397			print STDERR "DEBUG: make_variant: a1 = $a1; a2 = $a2\n" if $debug;
398			if ($a1 eq "") { $a1 = $a2; }
399			elsif ($a1 ne "" && $a2 ne "") { $a1 .= ",".$a2; }
400			if ($a eq $s)
401			{
402				if (!defined($variant_cnt{$s}))
403				{
404					$variant_cnt{$s} = 0;
405				}
406				$variant_cnt{$s}++;
407				$a .= "{$variant_cnt{$s}}";
408			}
409			my $toadd = $a.":".$a1.(defined($k)?":".$k:"");
410			my $togrep = $s.'(\{[0-9]+\})?:'.$a1.(defined($k)?":".$k:"");
411			if (!grep(/^$togrep$/,
412				  split(/;/, defined($variant{$s})?$variant{$s}:""))) {
413				if (defined($variant{$s})) { $variant{$s} .= ";"; }
414				$variant{$s} .= $toadd;
415			}
416			print STDERR "DEBUG: make_variant: Exit with variant of ",$s," = ",$variant{$s},"\n" if $debug;
417		};
418
419		print STDERR "DEBUG: parsing ----------\n" if $debug;
420		while(<IN>) {
421			last if (/\/\* Error codes for the \w+ functions\. \*\//);
422			if ($line ne '') {
423				$_ = $line . $_;
424				$line = '';
425			}
426
427			if (/\\$/) {
428				chomp; # remove eol
429				chop; # remove ending backslash
430				$line = $_;
431				next;
432			}
433
434	    		$cpp = 1 if /^\#.*ifdef.*cplusplus/;
435			if ($cpp) {
436				$cpp = 0 if /^\#.*endif/;
437				next;
438	    		}
439
440			s/\/\*.*?\*\///gs;                   # ignore comments
441			s/{[^{}]*}//gs;                      # ignore {} blocks
442			print STDERR "DEBUG: \$_=\"$_\"\n" if $debug;
443			if (/^\#\s*ifndef\s+(.*)/) {
444				push(@tag,"-");
445				push(@tag,$1);
446				$tag{$1}=-1;
447				print STDERR "DEBUG: $file: found tag $1 = -1\n" if $debug;
448			} elsif (/^\#\s*if\s+!defined\(([^\)]+)\)/) {
449				push(@tag,"-");
450				if (/^\#\s*if\s+(!defined\(([^\)]+)\)(\s+\&\&\s+!defined\(([^\)]+)\))*)$/) {
451					my $tmp_1 = $1;
452					my $tmp_;
453					foreach $tmp_ (split '\&\&',$tmp_1) {
454						$tmp_ =~ /!defined\(([^\)]+)\)/;
455						print STDERR "DEBUG: $file: found tag $1 = -1\n" if $debug;
456						push(@tag,$1);
457						$tag{$1}=-1;
458					}
459				} else {
460					print STDERR "Warning: $file: complicated expression: $_" if $debug; # because it is O...
461					print STDERR "DEBUG: $file: found tag $1 = -1\n" if $debug;
462					push(@tag,$1);
463					$tag{$1}=-1;
464				}
465			} elsif (/^\#\s*ifdef\s+(.*)/) {
466				push(@tag,"-");
467				push(@tag,$1);
468				$tag{$1}=1;
469				print STDERR "DEBUG: $file: found tag $1 = 1\n" if $debug;
470			} elsif (/^\#\s*if\s+defined\(([^\)]+)\)/) {
471				push(@tag,"-");
472				if (/^\#\s*if\s+(defined\(([^\)]+)\)(\s+\|\|\s+defined\(([^\)]+)\))*)$/) {
473					my $tmp_1 = $1;
474					my $tmp_;
475					foreach $tmp_ (split '\|\|',$tmp_1) {
476						$tmp_ =~ /defined\(([^\)]+)\)/;
477						print STDERR "DEBUG: $file: found tag $1 = 1\n" if $debug;
478						push(@tag,$1);
479						$tag{$1}=1;
480					}
481				} else {
482					print STDERR "Warning: $file: complicated expression: $_\n" if $debug; # because it is O...
483					print STDERR "DEBUG: $file: found tag $1 = 1\n" if $debug;
484					push(@tag,$1);
485					$tag{$1}=1;
486				}
487			} elsif (/^\#\s*error\s+(\w+) is disabled\./) {
488				my $tag_i = $#tag;
489				while($tag[$tag_i] ne "-") {
490					if ($tag[$tag_i] eq "OPENSSL_NO_".$1) {
491						$tag{$tag[$tag_i]}=2;
492						print STDERR "DEBUG: $file: chaged tag $1 = 2\n" if $debug;
493					}
494					$tag_i--;
495				}
496			} elsif (/^\#\s*endif/) {
497				my $tag_i = $#tag;
498				while($tag[$tag_i] ne "-") {
499					my $t=$tag[$tag_i];
500					print STDERR "DEBUG: \$t=\"$t\"\n" if $debug;
501					if ($tag{$t}==2) {
502						$tag{$t}=-1;
503					} else {
504						$tag{$t}=0;
505					}
506					print STDERR "DEBUG: $file: changed tag ",$t," = ",$tag{$t},"\n" if $debug;
507					pop(@tag);
508					if ($t =~ /^OPENSSL_NO_([A-Z0-9_]+)$/) {
509						$t=$1;
510					} else {
511						$t="";
512					}
513					if ($t ne ""
514					    && !grep(/^$t$/, @known_algorithms)) {
515						$unknown_algorithms{$t} = 1;
516						#print STDERR "DEBUG: Added as unknown algorithm: $t\n" if $debug;
517					}
518					$tag_i--;
519				}
520				pop(@tag);
521			} elsif (/^\#\s*else/) {
522				my $tag_i = $#tag;
523				while($tag[$tag_i] ne "-") {
524					my $t=$tag[$tag_i];
525					$tag{$t}= -$tag{$t};
526					print STDERR "DEBUG: $file: changed tag ",$t," = ",$tag{$t},"\n" if $debug;
527					$tag_i--;
528				}
529			} elsif (/^\#\s*if\s+1/) {
530				push(@tag,"-");
531				# Dummy tag
532				push(@tag,"TRUE");
533				$tag{"TRUE"}=1;
534				print STDERR "DEBUG: $file: found 1\n" if $debug;
535			} elsif (/^\#\s*if\s+0/) {
536				push(@tag,"-");
537				# Dummy tag
538				push(@tag,"TRUE");
539				$tag{"TRUE"}=-1;
540				print STDERR "DEBUG: $file: found 0\n" if $debug;
541			} elsif (/^\#\s*define\s+(\w+)\s+(\w+)/
542				 && $symhacking && $tag{'TRUE'} != -1) {
543				# This is for aliasing.  When we find an alias,
544				# we have to invert
545				&$make_variant($1,$2);
546				print STDERR "DEBUG: $file: defined $1 = $2\n" if $debug;
547			}
548			if (/^\#/) {
549				@current_platforms =
550				    grep(!/^$/,
551					 map { $tag{$_} == 1 ? $_ :
552						   $tag{$_} == -1 ? "!".$_  : "" }
553					 @known_platforms);
554				push @current_platforms
555				    , grep(!/^$/,
556					   map { $tag{"OPENSSL_SYS_".$_} == 1 ? $_ :
557						     $tag{"OPENSSL_SYS_".$_} == -1 ? "!".$_  : "" }
558					   @known_ossl_platforms);
559				@current_algorithms =
560				    grep(!/^$/,
561					 map { $tag{"OPENSSL_NO_".$_} == -1 ? $_ : "" }
562					 @known_algorithms);
563				$def .=
564				    "#INFO:"
565					.join(',',@current_platforms).":"
566					    .join(',',@current_algorithms).";";
567				next;
568			}
569			if ($tag{'TRUE'} != -1) {
570				if (/^\s*DECLARE_STACK_OF\s*\(\s*(\w*)\s*\)/) {
571					next;
572				} elsif (/^\s*DECLARE_ASN1_ENCODE_FUNCTIONS\s*\(\s*(\w*)\s*,\s*(\w*)\s*,\s*(\w*)\s*\)/) {
573					$def .= "int d2i_$3(void);";
574					$def .= "int i2d_$3(void);";
575					# Variant for platforms that do not
576					# have to access globale variables
577					# in shared libraries through functions
578					$def .=
579					    "#INFO:"
580						.join(',',"!EXPORT_VAR_AS_FUNCTION",@current_platforms).":"
581						    .join(',',@current_algorithms).";";
582					$def .= "OPENSSL_EXTERN int $2_it;";
583					$def .=
584					    "#INFO:"
585						.join(',',@current_platforms).":"
586						    .join(',',@current_algorithms).";";
587					# Variant for platforms that have to
588					# access globale variables in shared
589					# libraries through functions
590					&$make_variant("$2_it","$2_it",
591						      "EXPORT_VAR_AS_FUNCTION",
592						      "FUNCTION");
593					next;
594				} elsif (/^\s*DECLARE_ASN1_FUNCTIONS_fname\s*\(\s*(\w*)\s*,\s*(\w*)\s*,\s*(\w*)\s*\)/) {
595					$def .= "int d2i_$3(void);";
596					$def .= "int i2d_$3(void);";
597					$def .= "int $3_free(void);";
598					$def .= "int $3_new(void);";
599					# Variant for platforms that do not
600					# have to access globale variables
601					# in shared libraries through functions
602					$def .=
603					    "#INFO:"
604						.join(',',"!EXPORT_VAR_AS_FUNCTION",@current_platforms).":"
605						    .join(',',@current_algorithms).";";
606					$def .= "OPENSSL_EXTERN int $2_it;";
607					$def .=
608					    "#INFO:"
609						.join(',',@current_platforms).":"
610						    .join(',',@current_algorithms).";";
611					# Variant for platforms that have to
612					# access globale variables in shared
613					# libraries through functions
614					&$make_variant("$2_it","$2_it",
615						      "EXPORT_VAR_AS_FUNCTION",
616						      "FUNCTION");
617					next;
618				} elsif (/^\s*DECLARE_ASN1_FUNCTIONS\s*\(\s*(\w*)\s*\)/ ||
619					 /^\s*DECLARE_ASN1_FUNCTIONS_const\s*\(\s*(\w*)\s*\)/) {
620					$def .= "int d2i_$1(void);";
621					$def .= "int i2d_$1(void);";
622					$def .= "int $1_free(void);";
623					$def .= "int $1_new(void);";
624					# Variant for platforms that do not
625					# have to access globale variables
626					# in shared libraries through functions
627					$def .=
628					    "#INFO:"
629						.join(',',"!EXPORT_VAR_AS_FUNCTION",@current_platforms).":"
630						    .join(',',@current_algorithms).";";
631					$def .= "OPENSSL_EXTERN int $1_it;";
632					$def .=
633					    "#INFO:"
634						.join(',',@current_platforms).":"
635						    .join(',',@current_algorithms).";";
636					# Variant for platforms that have to
637					# access globale variables in shared
638					# libraries through functions
639					&$make_variant("$1_it","$1_it",
640						      "EXPORT_VAR_AS_FUNCTION",
641						      "FUNCTION");
642					next;
643				} elsif (/^\s*DECLARE_ASN1_ENCODE_FUNCTIONS_const\s*\(\s*(\w*)\s*,\s*(\w*)\s*\)/) {
644					$def .= "int d2i_$2(void);";
645					$def .= "int i2d_$2(void);";
646					# Variant for platforms that do not
647					# have to access globale variables
648					# in shared libraries through functions
649					$def .=
650					    "#INFO:"
651						.join(',',"!EXPORT_VAR_AS_FUNCTION",@current_platforms).":"
652						    .join(',',@current_algorithms).";";
653					$def .= "OPENSSL_EXTERN int $2_it;";
654					$def .=
655					    "#INFO:"
656						.join(',',@current_platforms).":"
657						    .join(',',@current_algorithms).";";
658					# Variant for platforms that have to
659					# access globale variables in shared
660					# libraries through functions
661					&$make_variant("$2_it","$2_it",
662						      "EXPORT_VAR_AS_FUNCTION",
663						      "FUNCTION");
664					next;
665				} elsif (/^\s*DECLARE_ASN1_FUNCTIONS_name\s*\(\s*(\w*)\s*,\s*(\w*)\s*\)/) {
666					$def .= "int d2i_$2(void);";
667					$def .= "int i2d_$2(void);";
668					$def .= "int $2_free(void);";
669					$def .= "int $2_new(void);";
670					# Variant for platforms that do not
671					# have to access globale variables
672					# in shared libraries through functions
673					$def .=
674					    "#INFO:"
675						.join(',',"!EXPORT_VAR_AS_FUNCTION",@current_platforms).":"
676						    .join(',',@current_algorithms).";";
677					$def .= "OPENSSL_EXTERN int $2_it;";
678					$def .=
679					    "#INFO:"
680						.join(',',@current_platforms).":"
681						    .join(',',@current_algorithms).";";
682					# Variant for platforms that have to
683					# access globale variables in shared
684					# libraries through functions
685					&$make_variant("$2_it","$2_it",
686						      "EXPORT_VAR_AS_FUNCTION",
687						      "FUNCTION");
688					next;
689				} elsif (/^\s*DECLARE_ASN1_ITEM\s*\(\s*(\w*)\s*\)/) {
690					# Variant for platforms that do not
691					# have to access globale variables
692					# in shared libraries through functions
693					$def .=
694					    "#INFO:"
695						.join(',',"!EXPORT_VAR_AS_FUNCTION",@current_platforms).":"
696						    .join(',',@current_algorithms).";";
697					$def .= "OPENSSL_EXTERN int $1_it;";
698					$def .=
699					    "#INFO:"
700						.join(',',@current_platforms).":"
701						    .join(',',@current_algorithms).";";
702					# Variant for platforms that have to
703					# access globale variables in shared
704					# libraries through functions
705					&$make_variant("$1_it","$1_it",
706						      "EXPORT_VAR_AS_FUNCTION",
707						      "FUNCTION");
708					next;
709				} elsif (/^\s*DECLARE_ASN1_SET_OF\s*\(\s*(\w*)\s*\)/) {
710					next;
711				} elsif (/^\s*DECLARE_PKCS12_STACK_OF\s*\(\s*(\w*)\s*\)/) {
712					next;
713				} elsif (/^DECLARE_PEM_rw\s*\(\s*(\w*)\s*,/ ||
714					 /^DECLARE_PEM_rw_cb\s*\(\s*(\w*)\s*,/ ) {
715					# Things not in Win16
716					$def .=
717					    "#INFO:"
718						.join(',',"!WIN16",@current_platforms).":"
719						    .join(',',@current_algorithms).";";
720					$def .= "int PEM_read_$1(void);";
721					$def .= "int PEM_write_$1(void);";
722					$def .=
723					    "#INFO:"
724						.join(',',@current_platforms).":"
725						    .join(',',@current_algorithms).";";
726					# Things that are everywhere
727					$def .= "int PEM_read_bio_$1(void);";
728					$def .= "int PEM_write_bio_$1(void);";
729					next;
730				} elsif (/^DECLARE_PEM_write\s*\(\s*(\w*)\s*,/ ||
731					 /^DECLARE_PEM_write_cb\s*\(\s*(\w*)\s*,/ ) {
732					# Things not in Win16
733					$def .=
734					    "#INFO:"
735						.join(',',"!WIN16",@current_platforms).":"
736						    .join(',',@current_algorithms).";";
737					$def .= "int PEM_write_$1(void);";
738					$def .=
739					    "#INFO:"
740						.join(',',@current_platforms).":"
741						    .join(',',@current_algorithms).";";
742					# Things that are everywhere
743					$def .= "int PEM_write_bio_$1(void);";
744					next;
745				} elsif (/^DECLARE_PEM_read\s*\(\s*(\w*)\s*,/ ||
746					 /^DECLARE_PEM_read_cb\s*\(\s*(\w*)\s*,/ ) {
747					# Things not in Win16
748					$def .=
749					    "#INFO:"
750						.join(',',"!WIN16",@current_platforms).":"
751						    .join(',',@current_algorithms).";";
752					$def .= "int PEM_read_$1(void);";
753					$def .=
754					    "#INFO:"
755						.join(',',@current_platforms).":"
756						    .join(',',@current_algorithms).";";
757					# Things that are everywhere
758					$def .= "int PEM_read_bio_$1(void);";
759					next;
760				} elsif (/^OPENSSL_DECLARE_GLOBAL\s*\(\s*(\w*)\s*,\s*(\w*)\s*\)/) {
761					# Variant for platforms that do not
762					# have to access globale variables
763					# in shared libraries through functions
764					$def .=
765					    "#INFO:"
766						.join(',',"!EXPORT_VAR_AS_FUNCTION",@current_platforms).":"
767						    .join(',',@current_algorithms).";";
768					$def .= "OPENSSL_EXTERN int _shadow_$2;";
769					$def .=
770					    "#INFO:"
771						.join(',',@current_platforms).":"
772						    .join(',',@current_algorithms).";";
773					# Variant for platforms that have to
774					# access globale variables in shared
775					# libraries through functions
776					&$make_variant("_shadow_$2","_shadow_$2",
777						      "EXPORT_VAR_AS_FUNCTION",
778						      "FUNCTION");
779				} elsif ($tag{'CONST_STRICT'} != 1) {
780					if (/\{|\/\*|\([^\)]*$/) {
781						$line = $_;
782					} else {
783						$def .= $_;
784					}
785				}
786			}
787		}
788		close(IN);
789
790		my $algs;
791		my $plays;
792
793		print STDERR "DEBUG: postprocessing ----------\n" if $debug;
794		foreach (split /;/, $def) {
795			my $s; my $k = "FUNCTION"; my $p; my $a;
796			s/^[\n\s]*//g;
797			s/[\n\s]*$//g;
798			next if(/\#undef/);
799			next if(/typedef\W/);
800			next if(/\#define/);
801
802			print STDERR "DEBUG: \$_ = \"$_\"\n" if $debug;
803			if (/^\#INFO:([^:]*):(.*)$/) {
804				$plats = $1;
805				$algs = $2;
806				print STDERR "DEBUG: found info on platforms ($plats) and algorithms ($algs)\n" if $debug;
807				next;
808			} elsif (/^\s*OPENSSL_EXTERN\s.*?(\w+(\{[0-9]+\})?)(\[[0-9]*\])*\s*$/) {
809				$s = $1;
810				$k = "VARIABLE";
811				print STDERR "DEBUG: found external variable $s\n" if $debug;
812			} elsif (/\(\*(\w*(\{[0-9]+\})?)\([^\)]+/) {
813				$s = $1;
814				print STDERR "DEBUG: found ANSI C function $s\n" if $debug;
815			} elsif (/\w+\W+(\w+)\W*\(\s*\)$/s) {
816				# K&R C
817				print STDERR "DEBUG: found K&R C function $s\n" if $debug;
818				next;
819			} elsif (/\w+\W+\w+(\{[0-9]+\})?\W*\(.*\)$/s) {
820				while (not /\(\)$/s) {
821					s/[^\(\)]*\)$/\)/s;
822					s/\([^\(\)]*\)\)$/\)/s;
823				}
824				s/\(void\)//;
825				/(\w+(\{[0-9]+\})?)\W*\(\)/s;
826				$s = $1;
827				print STDERR "DEBUG: found function $s\n" if $debug;
828			} elsif (/\(/ and not (/=/)) {
829				print STDERR "File $file: cannot parse: $_;\n";
830				next;
831			} else {
832				next;
833			}
834
835			$syms{$s} = 1;
836			$kind{$s} = $k;
837
838			$p = $plats;
839			$a = $algs;
840			$a .= ",BF" if($s =~ /EVP_bf/);
841			$a .= ",CAST" if($s =~ /EVP_cast/);
842			$a .= ",DES" if($s =~ /EVP_des/);
843			$a .= ",DSA" if($s =~ /EVP_dss/);
844			$a .= ",IDEA" if($s =~ /EVP_idea/);
845			$a .= ",MD2" if($s =~ /EVP_md2/);
846			$a .= ",MD4" if($s =~ /EVP_md4/);
847			$a .= ",MD5" if($s =~ /EVP_md5/);
848			$a .= ",RC2" if($s =~ /EVP_rc2/);
849			$a .= ",RC4" if($s =~ /EVP_rc4/);
850			$a .= ",RC5" if($s =~ /EVP_rc5/);
851			$a .= ",RIPEMD" if($s =~ /EVP_ripemd/);
852			$a .= ",SHA" if($s =~ /EVP_sha/);
853			$a .= ",RSA" if($s =~ /EVP_(Open|Seal)(Final|Init)/);
854			$a .= ",RSA" if($s =~ /PEM_Seal(Final|Init|Update)/);
855			$a .= ",RSA" if($s =~ /RSAPrivateKey/);
856			$a .= ",RSA" if($s =~ /SSLv23?_((client|server)_)?method/);
857
858			$platform{$s} =
859			    &reduce_platforms((defined($platform{$s})?$platform{$s}.',':"").$p);
860			$algorithm{$s} .= ','.$a;
861
862			if (defined($variant{$s})) {
863				foreach $v (split /;/,$variant{$s}) {
864					(my $r, my $p, my $k) = split(/:/,$v);
865					my $ip = join ',',map({ /^!(.*)$/ ? $1 : "!".$_ } split /,/, $p);
866					$syms{$r} = 1;
867					if (!defined($k)) { $k = $kind{$s}; }
868					$kind{$r} = $k."(".$s.")";
869					$algorithm{$r} = $algorithm{$s};
870					$platform{$r} = &reduce_platforms($platform{$s}.",".$p.",".$p);
871					$platform{$s} = &reduce_platforms($platform{$s}.','.$ip.','.$ip);
872					print STDERR "DEBUG: \$variant{\"$s\"} = ",$v,"; \$r = $r; \$p = ",$platform{$r},"; \$a = ",$algorithm{$r},"; \$kind = ",$kind{$r},"\n" if $debug;
873				}
874			}
875			print STDERR "DEBUG: \$s = $s; \$p = ",$platform{$s},"; \$a = ",$algorithm{$s},"; \$kind = ",$kind{$s},"\n" if $debug;
876		}
877	}
878
879	# Prune the returned symbols
880
881        delete $syms{"bn_dump1"};
882	$platform{"BIO_s_log"} .= ",!WIN32,!WIN16,!macintosh";
883
884	$platform{"PEM_read_NS_CERT_SEQ"} = "VMS";
885	$platform{"PEM_write_NS_CERT_SEQ"} = "VMS";
886	$platform{"PEM_read_P8_PRIV_KEY_INFO"} = "VMS";
887	$platform{"PEM_write_P8_PRIV_KEY_INFO"} = "VMS";
888
889	# Info we know about
890
891	push @ret, map { $_."\\".&info_string($_,"EXIST",
892					      $platform{$_},
893					      $kind{$_},
894					      $algorithm{$_}) } keys %syms;
895
896	if (keys %unknown_algorithms) {
897		print STDERR "WARNING: mkdef.pl doesn't know the following algorithms:\n";
898		print STDERR "\t",join("\n\t",keys %unknown_algorithms),"\n";
899	}
900	return(@ret);
901}
902
903# Param: string of comma-separated platform-specs.
904sub reduce_platforms
905{
906	my ($platforms) = @_;
907	my $pl = defined($platforms) ? $platforms : "";
908	my %p = map { $_ => 0 } split /,/, $pl;
909	my $ret;
910
911	print STDERR "DEBUG: Entered reduce_platforms with \"$platforms\"\n"
912	    if $debug;
913	# We do this, because if there's code like the following, it really
914	# means the function exists in all cases and should therefore be
915	# everywhere.  By increasing and decreasing, we may attain 0:
916	#
917	# ifndef WIN16
918	#    int foo();
919	# else
920	#    int _fat foo();
921	# endif
922	foreach $platform (split /,/, $pl) {
923		if ($platform =~ /^!(.*)$/) {
924			$p{$1}--;
925		} else {
926			$p{$platform}++;
927		}
928	}
929	foreach $platform (keys %p) {
930		if ($p{$platform} == 0) { delete $p{$platform}; }
931	}
932
933	delete $p{""};
934
935	$ret = join(',',sort(map { $p{$_} < 0 ? "!".$_ : $_ } keys %p));
936	print STDERR "DEBUG: Exiting reduce_platforms with \"$ret\"\n"
937	    if $debug;
938	return $ret;
939}
940
941sub info_string {
942	(my $symbol, my $exist, my $platforms, my $kind, my $algorithms) = @_;
943
944	my %a = defined($algorithms) ?
945	    map { $_ => 1 } split /,/, $algorithms : ();
946	my $k = defined($kind) ? $kind : "FUNCTION";
947	my $ret;
948	my $p = &reduce_platforms($platforms);
949
950	delete $a{""};
951
952	$ret = $exist;
953	$ret .= ":".$p;
954	$ret .= ":".$k;
955	$ret .= ":".join(',',sort keys %a);
956	return $ret;
957}
958
959sub maybe_add_info {
960	(my $name, *nums, my @symbols) = @_;
961	my $sym;
962	my $new_info = 0;
963	my %syms=();
964
965	print STDERR "Updating $name info\n";
966	foreach $sym (@symbols) {
967		(my $s, my $i) = split /\\/, $sym;
968		if (defined($nums{$s})) {
969			$i =~ s/^(.*?:.*?:\w+)(\(\w+\))?/$1/;
970			(my $n, my $dummy) = split /\\/, $nums{$s};
971			if (!defined($dummy) || $i ne $dummy) {
972				$nums{$s} = $n."\\".$i;
973				$new_info++;
974				print STDERR "DEBUG: maybe_add_info for $s: \"$dummy\" => \"$i\"\n" if $debug;
975			}
976		}
977		$syms{$s} = 1;
978	}
979
980	my @s=sort { &parse_number($nums{$a},"n") <=> &parse_number($nums{$b},"n") } keys %nums;
981	foreach $sym (@s) {
982		(my $n, my $i) = split /\\/, $nums{$sym};
983		if (!defined($syms{$sym}) && $i !~ /^NOEXIST:/) {
984			$new_info++;
985			print STDERR "DEBUG: maybe_add_info for $sym: -> undefined\n" if $debug;
986		}
987	}
988	if ($new_info) {
989		print STDERR "$new_info old symbols got an info update\n";
990		if (!$do_rewrite) {
991			print STDERR "You should do a rewrite to fix this.\n";
992		}
993	} else {
994		print STDERR "No old symbols needed info update\n";
995	}
996}
997
998# Param: string of comma-separated keywords, each possibly prefixed with a "!"
999sub is_valid
1000{
1001	my ($keywords_txt,$platforms) = @_;
1002	my (@keywords) = split /,/,$keywords_txt;
1003	my ($falsesum, $truesum) = (0, !grep(/^[^!]/,@keywords));
1004
1005	# Param: one keyword
1006	sub recognise
1007	{
1008		my ($keyword,$platforms) = @_;
1009
1010		if ($platforms) {
1011			# platforms
1012			if ($keyword eq "VMS" && $VMS) { return 1; }
1013			if ($keyword eq "WIN32" && $W32) { return 1; }
1014			if ($keyword eq "WIN16" && $W16) { return 1; }
1015			if ($keyword eq "WINNT" && $NT) { return 1; }
1016			if ($keyword eq "OS2" && $OS2) { return 1; }
1017			# Special platforms:
1018			# EXPORT_VAR_AS_FUNCTION means that global variables
1019			# will be represented as functions.  This currently
1020			# only happens on VMS-VAX.
1021			if ($keyword eq "EXPORT_VAR_AS_FUNCTION" && ($VMSVAX || $W32 || $W16)) {
1022				return 1;
1023			}
1024			return 0;
1025		} else {
1026			# algorithms
1027			if ($keyword eq "RC2" && $no_rc2) { return 0; }
1028			if ($keyword eq "RC4" && $no_rc4) { return 0; }
1029			if ($keyword eq "RC5" && $no_rc5) { return 0; }
1030			if ($keyword eq "IDEA" && $no_idea) { return 0; }
1031			if ($keyword eq "DES" && $no_des) { return 0; }
1032			if ($keyword eq "BF" && $no_bf) { return 0; }
1033			if ($keyword eq "CAST" && $no_cast) { return 0; }
1034			if ($keyword eq "MD2" && $no_md2) { return 0; }
1035			if ($keyword eq "MD4" && $no_md4) { return 0; }
1036			if ($keyword eq "MD5" && $no_md5) { return 0; }
1037			if ($keyword eq "SHA" && $no_sha) { return 0; }
1038			if ($keyword eq "RIPEMD" && $no_ripemd) { return 0; }
1039			if ($keyword eq "MDC2" && $no_mdc2) { return 0; }
1040			if ($keyword eq "RSA" && $no_rsa) { return 0; }
1041			if ($keyword eq "DSA" && $no_dsa) { return 0; }
1042			if ($keyword eq "DH" && $no_dh) { return 0; }
1043			if ($keyword eq "EC" && $no_ec) { return 0; }
1044			if ($keyword eq "HMAC" && $no_hmac) { return 0; }
1045			if ($keyword eq "AES" && $no_aes) { return 0; }
1046			if ($keyword eq "EVP" && $no_evp) { return 0; }
1047			if ($keyword eq "LHASH" && $no_lhash) { return 0; }
1048			if ($keyword eq "STACK" && $no_stack) { return 0; }
1049			if ($keyword eq "ERR" && $no_err) { return 0; }
1050			if ($keyword eq "BUFFER" && $no_buffer) { return 0; }
1051			if ($keyword eq "BIO" && $no_bio) { return 0; }
1052			if ($keyword eq "COMP" && $no_comp) { return 0; }
1053			if ($keyword eq "DSO" && $no_dso) { return 0; }
1054			if ($keyword eq "KRB5" && $no_krb5) { return 0; }
1055			if ($keyword eq "FP_API" && $no_fp_api) { return 0; }
1056
1057			# Nothing recognise as true
1058			return 1;
1059		}
1060	}
1061
1062	foreach $k (@keywords) {
1063		if ($k =~ /^!(.*)$/) {
1064			$falsesum += &recognise($1,$platforms);
1065		} else {
1066			$truesum += &recognise($k,$platforms);
1067		}
1068	}
1069	print STDERR "DEBUG: [",$#keywords,",",$#keywords < 0,"] is_valid($keywords_txt) => (\!$falsesum) && $truesum = ",(!$falsesum) && $truesum,"\n" if $debug;
1070	return (!$falsesum) && $truesum;
1071}
1072
1073sub print_test_file
1074{
1075	(*OUT,my $name,*nums,my $testall,my @symbols)=@_;
1076	my $n = 1; my @e; my @r;
1077	my $sym; my $prev = ""; my $prefSSLeay;
1078
1079	(@e)=grep(/^SSLeay(\{[0-9]+\})?\\.*?:.*?:.*/,@symbols);
1080	(@r)=grep(/^\w+(\{[0-9]+\})?\\.*?:.*?:.*/ && !/^SSLeay(\{[0-9]+\})?\\.*?:.*?:.*/,@symbols);
1081	@symbols=((sort @e),(sort @r));
1082
1083	foreach $sym (@symbols) {
1084		(my $s, my $i) = $sym =~ /^(.*?)\\(.*)$/;
1085		my $v = 0;
1086		$v = 1 if $i=~ /^.*?:.*?:VARIABLE/;
1087		my $p = ($i =~ /^[^:]*:([^:]*):/,$1);
1088		my $a = ($i =~ /^[^:]*:[^:]*:[^:]*:([^:]*)/,$1);
1089		if (!defined($nums{$s})) {
1090			print STDERR "Warning: $s does not have a number assigned\n"
1091			    if(!$do_update);
1092		} elsif (is_valid($p,1) && is_valid($a,0)) {
1093			my $s2 = ($s =~ /^(.*?)(\{[0-9]+\})?$/, $1);
1094			if ($prev eq $s2) {
1095				print OUT "\t/* The following has already appeared previously */\n";
1096				print STDERR "Warning: Symbol '",$s2,"' redefined. old=",($nums{$prev} =~ /^(.*?)\\/,$1),", new=",($nums{$s2} =~ /^(.*?)\\/,$1),"\n";
1097			}
1098			$prev = $s2;	# To warn about duplicates...
1099
1100			($nn,$ni)=($nums{$s2} =~ /^(.*?)\\(.*)$/);
1101			if ($v) {
1102				print OUT "\textern int $s2; /* type unknown */ /* $nn $ni */\n";
1103			} else {
1104				print OUT "\textern int $s2(); /* type unknown */ /* $nn $ni */\n";
1105			}
1106		}
1107	}
1108}
1109
1110sub print_def_file
1111{
1112	(*OUT,my $name,*nums,my @symbols)=@_;
1113	my $n = 1; my @e; my @r; my @v; my $prev="";
1114	my $liboptions="";
1115
1116	if ($W32)
1117		{ $name.="32"; }
1118	elsif ($W16)
1119		{ $name.="16"; }
1120	elsif ($OS2)
1121		{ $liboptions = "INITINSTANCE\nDATA NONSHARED"; }
1122
1123	print OUT <<"EOF";
1124;
1125; Definition file for the DLL version of the $name library from OpenSSL
1126;
1127
1128LIBRARY         $name	$liboptions
1129
1130DESCRIPTION     'OpenSSL $name - http://www.openssl.org/'
1131
1132EOF
1133
1134	if ($W16) {
1135		print <<"EOF";
1136CODE            PRELOAD MOVEABLE
1137DATA            PRELOAD MOVEABLE SINGLE
1138
1139EXETYPE		WINDOWS
1140
1141HEAPSIZE	4096
1142STACKSIZE	8192
1143
1144EOF
1145	}
1146
1147	print "EXPORTS\n";
1148
1149	(@e)=grep(/^SSLeay(\{[0-9]+\})?\\.*?:.*?:FUNCTION/,@symbols);
1150	(@r)=grep(/^\w+(\{[0-9]+\})?\\.*?:.*?:FUNCTION/ && !/^SSLeay(\{[0-9]+\})?\\.*?:.*?:FUNCTION/,@symbols);
1151	(@v)=grep(/^\w+(\{[0-9]+\})?\\.*?:.*?:VARIABLE/,@symbols);
1152	@symbols=((sort @e),(sort @r), (sort @v));
1153
1154
1155	foreach $sym (@symbols) {
1156		(my $s, my $i) = $sym =~ /^(.*?)\\(.*)$/;
1157		my $v = 0;
1158		$v = 1 if $i =~ /^.*?:.*?:VARIABLE/;
1159		if (!defined($nums{$s})) {
1160			printf STDERR "Warning: $s does not have a number assigned\n"
1161			    if(!$do_update);
1162		} else {
1163			(my $n, my $dummy) = split /\\/, $nums{$s};
1164			my %pf = ();
1165			my $p = ($i =~ /^[^:]*:([^:]*):/,$1);
1166			my $a = ($i =~ /^[^:]*:[^:]*:[^:]*:([^:]*)/,$1);
1167			if (is_valid($p,1) && is_valid($a,0)) {
1168				my $s2 = ($s =~ /^(.*?)(\{[0-9]+\})?$/, $1);
1169				if ($prev eq $s2) {
1170					print STDERR "Warning: Symbol '",$s2,"' redefined. old=",($nums{$prev} =~ /^(.*?)\\/,$1),", new=",($nums{$s2} =~ /^(.*?)\\/,$1),"\n";
1171				}
1172				$prev = $s2;	# To warn about duplicates...
1173				if($v && !$OS2) {
1174					printf OUT "    %s%-39s @%-8d DATA\n",($W32)?"":"_",$s2,$n;
1175				} else {
1176					printf OUT "    %s%-39s @%d\n",($W32||$OS2)?"":"_",$s2,$n;
1177				}
1178			}
1179		}
1180	}
1181	printf OUT "\n";
1182}
1183
1184sub load_numbers
1185{
1186	my($name)=@_;
1187	my(@a,%ret);
1188
1189	$max_num = 0;
1190	$num_noinfo = 0;
1191	$prev = "";
1192	$prev_cnt = 0;
1193
1194	open(IN,"<$name") || die "unable to open $name:$!\n";
1195	while (<IN>) {
1196		chop;
1197		s/#.*$//;
1198		next if /^\s*$/;
1199		@a=split;
1200		if (defined $ret{$a[0]}) {
1201			# This is actually perfectly OK
1202			#print STDERR "Warning: Symbol '",$a[0],"' redefined. old=",$ret{$a[0]},", new=",$a[1],"\n";
1203		}
1204		if ($max_num > $a[1]) {
1205			print STDERR "Warning: Number decreased from ",$max_num," to ",$a[1],"\n";
1206		}
1207		elsif ($max_num == $a[1]) {
1208			# This is actually perfectly OK
1209			#print STDERR "Warning: Symbol ",$a[0]," has same number as previous ",$prev,": ",$a[1],"\n";
1210			if ($a[0] eq $prev) {
1211				$prev_cnt++;
1212				$a[0] .= "{$prev_cnt}";
1213			}
1214		}
1215		else {
1216			$prev_cnt = 0;
1217		}
1218		if ($#a < 2) {
1219			# Existence will be proven later, in do_defs
1220			$ret{$a[0]}=$a[1];
1221			$num_noinfo++;
1222		} else {
1223			$ret{$a[0]}=$a[1]."\\".$a[2]; # \\ is a special marker
1224		}
1225		$max_num = $a[1] if $a[1] > $max_num;
1226		$prev=$a[0];
1227	}
1228	if ($num_noinfo) {
1229		print STDERR "Warning: $num_noinfo symbols were without info.";
1230		if ($do_rewrite) {
1231			printf STDERR "  The rewrite will fix this.\n";
1232		} else {
1233			printf STDERR "  You should do a rewrite to fix this.\n";
1234		}
1235	}
1236	close(IN);
1237	return(%ret);
1238}
1239
1240sub parse_number
1241{
1242	(my $str, my $what) = @_;
1243	(my $n, my $i) = split(/\\/,$str);
1244	if ($what eq "n") {
1245		return $n;
1246	} else {
1247		return $i;
1248	}
1249}
1250
1251sub rewrite_numbers
1252{
1253	(*OUT,$name,*nums,@symbols)=@_;
1254	my $thing;
1255
1256	print STDERR "Rewriting $name\n";
1257
1258	my @r = grep(/^\w+(\{[0-9]+\})?\\.*?:.*?:\w+\(\w+\)/,@symbols);
1259	my $r; my %r; my %rsyms;
1260	foreach $r (@r) {
1261		(my $s, my $i) = split /\\/, $r;
1262		my $a = $1 if $i =~ /^.*?:.*?:\w+\((\w+)\)/;
1263		$i =~ s/^(.*?:.*?:\w+)\(\w+\)/$1/;
1264		$r{$a} = $s."\\".$i;
1265		$rsyms{$s} = 1;
1266	}
1267
1268	my %syms = ();
1269	foreach $_ (@symbols) {
1270		(my $n, my $i) = split /\\/;
1271		$syms{$n} = 1;
1272	}
1273
1274	my @s=sort {
1275	    &parse_number($nums{$a},"n") <=> &parse_number($nums{$b},"n")
1276	    || $a cmp $b
1277	} keys %nums;
1278	foreach $sym (@s) {
1279		(my $n, my $i) = split /\\/, $nums{$sym};
1280		next if defined($i) && $i =~ /^.*?:.*?:\w+\(\w+\)/;
1281		next if defined($rsyms{$sym});
1282		print STDERR "DEBUG: rewrite_numbers for sym = ",$sym,": i = ",$i,", n = ",$n,", rsym{sym} = ",$rsyms{$sym},"syms{sym} = ",$syms{$sym},"\n" if $debug;
1283		$i="NOEXIST::FUNCTION:"
1284			if !defined($i) || $i eq "" || !defined($syms{$sym});
1285		my $s2 = $sym;
1286		$s2 =~ s/\{[0-9]+\}$//;
1287		printf OUT "%s%-39s %d\t%s\n","",$s2,$n,$i;
1288		if (exists $r{$sym}) {
1289			(my $s, $i) = split /\\/,$r{$sym};
1290			my $s2 = $s;
1291			$s2 =~ s/\{[0-9]+\}$//;
1292			printf OUT "%s%-39s %d\t%s\n","",$s2,$n,$i;
1293		}
1294	}
1295}
1296
1297sub update_numbers
1298{
1299	(*OUT,$name,*nums,my $start_num, my @symbols)=@_;
1300	my $new_syms = 0;
1301
1302	print STDERR "Updating $name numbers\n";
1303
1304	my @r = grep(/^\w+(\{[0-9]+\})?\\.*?:.*?:\w+\(\w+\)/,@symbols);
1305	my $r; my %r; my %rsyms;
1306	foreach $r (@r) {
1307		(my $s, my $i) = split /\\/, $r;
1308		my $a = $1 if $i =~ /^.*?:.*?:\w+\((\w+)\)/;
1309		$i =~ s/^(.*?:.*?:\w+)\(\w+\)/$1/;
1310		$r{$a} = $s."\\".$i;
1311		$rsyms{$s} = 1;
1312	}
1313
1314	foreach $sym (@symbols) {
1315		(my $s, my $i) = $sym =~ /^(.*?)\\(.*)$/;
1316		next if $i =~ /^.*?:.*?:\w+\(\w+\)/;
1317		next if defined($rsyms{$sym});
1318		die "ERROR: Symbol $sym had no info attached to it."
1319		    if $i eq "";
1320		if (!exists $nums{$s}) {
1321			$new_syms++;
1322			my $s2 = $s;
1323			$s2 =~ s/\{[0-9]+\}$//;
1324			printf OUT "%s%-39s %d\t%s\n","",$s2, ++$start_num,$i;
1325			if (exists $r{$s}) {
1326				($s, $i) = split /\\/,$r{$s};
1327				$s =~ s/\{[0-9]+\}$//;
1328				printf OUT "%s%-39s %d\t%s\n","",$s, $start_num,$i;
1329			}
1330		}
1331	}
1332	if($new_syms) {
1333		print STDERR "$new_syms New symbols added\n";
1334	} else {
1335		print STDERR "No New symbols Added\n";
1336	}
1337}
1338
1339sub check_existing
1340{
1341	(*nums, my @symbols)=@_;
1342	my %existing; my @remaining;
1343	@remaining=();
1344	foreach $sym (@symbols) {
1345		(my $s, my $i) = $sym =~ /^(.*?)\\(.*)$/;
1346		$existing{$s}=1;
1347	}
1348	foreach $sym (keys %nums) {
1349		if (!exists $existing{$sym}) {
1350			push @remaining, $sym;
1351		}
1352	}
1353	if(@remaining) {
1354		print STDERR "The following symbols do not seem to exist:\n";
1355		foreach $sym (@remaining) {
1356			print STDERR "\t",$sym,"\n";
1357		}
1358	}
1359}
1360
1361