+sub count_parens
+{
+ my $line = shift(@_);
+
+ my $open = $line =~ tr/\(//;
+ my $close = $line =~ tr/\)//;
+
+ return $open - $close;
+}
+
+#Parse opensslv.h to get the current version number. Also work out the base
+#version, i.e. the lowest version number that is binary compatible with this
+#version
+sub get_openssl_version()
+{
+ my $fn = catfile($config{sourcedir},"include","openssl","opensslv.h");
+ open (IN, "$fn") || die "Can't open opensslv.h";
+
+ while(<IN>) {
+ if (/OPENSSL_VERSION_TEXT\s+"OpenSSL (\d\.\d\.)(\d[a-z]*)(-| )/) {
+ my $suffix = $2;
+ (my $baseversion = $1) =~ s/\./_/g;
+ close IN;
+ return ($baseversion."0", $baseversion.$suffix);
+ }
+ }
+ die "Can't find OpenSSL version number\n";
+}
+
+#Given an OpenSSL version number, calculate the next version number. If the
+#version number gets to a.b.czz then we go to a.b.(c+1)
+sub get_next_version()
+{
+ my $thisversion = shift;
+
+ my ($base, $letter) = $thisversion =~ /^(\d_\d_\d)([a-z]{0,2})$/;
+
+ if ($letter eq "zz") {
+ my $lastnum = substr($base, -1);
+ return substr($base, 0, length($base)-1).(++$lastnum);
+ }
+ return $base.get_next_letter($letter);
+}
+
+#Given the letters off the end of an OpenSSL version string, calculate what
+#the letters for the next release would be.
+sub get_next_letter()
+{
+ my $thisletter = shift;
+ my $baseletter = "";
+ my $endletter;
+
+ if ($thisletter eq "") {
+ return "a";
+ }
+ if ((length $thisletter) > 1) {
+ ($baseletter, $endletter) = $thisletter =~ /([a-z]+)([a-z])/;
+ } else {
+ $endletter = $thisletter;
+ }
+
+ if ($endletter eq "z") {
+ return $thisletter."a";
+ } else {
+ return $baseletter.(++$endletter);
+ }
+}
+
+#Check if a version is less than or equal to the current version. Its a fatal
+#error if not. They must also only differ in letters, or the last number (i.e.
+#the first two numbers must be the same)
+sub check_version_lte()
+{
+ my ($testversion, $currversion) = @_;
+ my $lentv;
+ my $lencv;
+ my $cvbase;
+
+ my ($cvnums) = $currversion =~ /^(\d_\d_\d)[a-z]*$/;
+ my ($tvnums) = $testversion =~ /^(\d_\d_\d)[a-z]*$/;
+
+ #Die if we can't parse the version numbers or they don't look sane
+ die "Invalid version number: $testversion and $currversion\n"
+ if (!defined($cvnums) || !defined($tvnums)
+ || length($cvnums) != 5
+ || length($tvnums) != 5);
+
+ #If the base versions (without letters) don't match check they only differ
+ #in the last number
+ if ($cvnums ne $tvnums) {
+ die "Invalid version number: $testversion "
+ ."for current version $currversion\n"
+ if (substr($cvnums, -1) < substr($tvnums, -1)
+ || substr($cvnums, 0, 4) ne substr($tvnums, 0, 4));
+ return;
+ }
+ #If we get here then the base version (i.e. the numbers) are the same - they
+ #only differ in the letters
+
+ $lentv = length $testversion;
+ $lencv = length $currversion;
+
+ #If the testversion has more letters than the current version then it must
+ #be later (or malformed)
+ if ($lentv > $lencv) {
+ die "Invalid version number: $testversion "
+ ."is greater than $currversion\n";
+ }
+
+ #Get the last letter from the current version
+ my ($cvletter) = $currversion =~ /([a-z])$/;
+ if (defined $cvletter) {
+ ($cvbase) = $currversion =~ /(\d_\d_\d[a-z]*)$cvletter$/;
+ } else {
+ $cvbase = $currversion;
+ }
+ die "Unable to parse version number $currversion" if (!defined $cvbase);
+ my $tvbase;
+ my ($tvletter) = $testversion =~ /([a-z])$/;
+ if (defined $tvletter) {
+ ($tvbase) = $testversion =~ /(\d_\d_\d[a-z]*)$tvletter$/;
+ } else {
+ $tvbase = $testversion;
+ }
+ die "Unable to parse version number $testversion" if (!defined $tvbase);
+
+ if ($lencv > $lentv) {
+ #If current version has more letters than testversion then testversion
+ #minus the final letter must be a substring of the current version
+ die "Invalid version number $testversion "
+ ."is greater than $currversion or is invalid\n"
+ if (index($cvbase, $tvbase) != 0);
+ } else {
+ #If both versions have the same number of letters then they must be
+ #equal up to the last letter, and the last letter in testversion must
+ #be less than or equal to the last letter in current version.
+ die "Invalid version number $testversion "
+ ."is greater than $currversion\n"
+ if (($cvbase ne $tvbase) && ($tvletter gt $cvletter));
+ }
+}
+
+sub do_deprecated()
+{
+ my ($decl, $plats, $algs) = @_;
+ $decl =~ /^\s*(DEPRECATEDIN_\d+_\d+_\d+)\s*\((.*)\)\s*$/
+ or die "Bad DEPRECTEDIN: $decl\n";
+ my $info1 .= "#INFO:";
+ $info1 .= join(',', @{$plats}) . ":";
+ my $info2 = $info1;
+ $info1 .= join(',',@{$algs}, $1) . ";";
+ $info2 .= join(',',@{$algs}) . ";";
+ return $info1 . $2 . ";" . $info2;
+}