#! /bin/sh
perl -x -S $0 "$@"
exit

#! perl
require 5.003;
use strict;

# Copyright by The HDF Group.
# Copyright by the Board of Trustees of the University of Illinois.
# All rights reserved.
#
# This file is part of HDF.  The full HDF copyright notice, including
# terms governing use, modification, and redistribution, is contained in
# the COPYING file, which can be found at the root of the source code
# distribution tree, or in https://support.hdfgroup.org/ftp/HDF/releases/.
# If you do not have access to either file, you may request a copy from
# help@hdfgroup.org.
#
#
# Robb Matzke <matzke@llnl.gov>
# 17 July 1998
#
# HDF4 alterations
# Larry Knox <lrknox@hdfgroup.org>
# 25 September 2009

### Purpose
# Increments the hdf4 version number by changing the value of
# constants in the hdf/src/hfile.h file.  The new version number is
# printed on the standard output. An alternate source file name can be
# specified as an argument.  In any case, the original file is saved
# by appending a tilde `~' to the name.

### Usage:
# h4vers [OPTIONS] [FILE]

# Without options this program only displays the current version and
# doesn't modify any files or create backups.  The default is to print
# The space and parentheses around A are only printed if A is not empty.
#
# The `-s VERSION' switch will set the version as specified.  If the
# string contains a dotted triple then it will be used as the version
# number, otherwise up to three numbers will be read from the end of
# the string and used as the major version, minor version, and release
# number.  If any numbers are missing then zero is assumed.  This
# allows versions to be specified like `-s "version 4.2 release 4"' or
# `-s hdf4-4.2.4.tar.bz2'.  If the new version is less than the old
# version then a warning message is generated on standard error. The
# annotation string, A, is set only if it appears immediately after the
# third number, separated by a dash (e.g., `1.2.3-pre1') or in parentheses
# (e.g., `version 1.2 release 3 (pre1)').
#
# The `-i [major|minor|release|annot|last]' option increments the major
# number, minor number, release number, or annotation string. The `last'
# switch increments the annotation string if present, otherwise the
# release number. If the release number is incremented then the annotation
# string is cleared.  If the minor number is incremented then the release
# number is set to zero and the annotation string is cleared; if the major
# number is incremented then the minor and release numbers are set to zero
# and the annotation string is cleared.
#
# If a file is specified then that file is used instead of
# ./hfile.h or ./hdf/src/hfile.h.
#
# If the version number is changed (either `-s' or `-i' was used on
# the command line) then the first line of the README.txt and
# release_notes/RELEASE.txt two levels above the hfile.h file are also
# modified so it looks something like: This is hdf4-1.2.3-pre1 currently
# under development. The AC_INIT macro in configure.in will also change
# in this case to be something like: AC_INIT([HDF4], [hdf4-1.2.3-pre1],
# [help@hdfgroup.org]).
#
#Following paragraph from h5vers does not apply for HDF4?
# Whenever the version changes, this script will increment the revision
# field in HDF4's libtool shared library version in config/lt_vers.am,
# which is included in src/Makefile.am.  Incrementing the revision field
# indicates that the source code has changed since the last version
# (which it probably has).
##############################################################################


sub getvers {
  local ($_) = @_;
  my (@vers);

  ($vers[0]) = /^\#\s*define\s+LIBVER_MAJOR\s+(\d+)/m;
  ($vers[1]) = /^\#\s*define\s+LIBVER_MINOR\s+(\d+)/m;
  ($vers[2]) = /^\#\s*define\s+LIBVER_RELEASE\s+(\d+)/m;
  ($vers[3]) = /^\#\s*define\s+LIBVER_SUBRELEASE\s+\"([^\"]*)\"/m;
  ($vers[4]) =  /^\#\s*define\s+LIBVER_STRING\s+\"([^\"]*\d+)\"/m;
  #The above gets the entire string, below would get just the date portion.
  #($vers[4]) =  /^\#\s*define\s+LIBVER_STRING\s+\"[^\"]*,(.*,\s+\d+)\"/m;
  return @vers;
}

sub setvers {
  my ($contents, @vers) = @_;
  my @months = ('January', 'February', 'March', 'April', 'May', 'June', 'July',
                'August', 'September', 'October', 'November', 'December');
  my @date = (localtime(time));
  $_[0] =~ s/^(\#\s*define\s+LIBVER_MAJOR\s+)\d+/$1$vers[0]/m;
  $_[0] =~ s/^(\#\s*define\s+LIBVER_MINOR\s+)\d+/$1$vers[1]/m;
  $_[0] =~ s/^(\#\s*define\s+LIBVER_RELEASE\s+)\d+/$1$vers[2]/m;
  $_[0] =~ s/^(\#\s*define\s+LIBVER_SUBRELEASE\s+\")[^\"]*/$1$vers[3]/m;
  $_[0] =~ s/^(\#\s*define\s+LIBVER_STRING\s+\")[^\"]*/
            sprintf("%sHDF Version %d.%d Release %d%s%s, %s %d, %d", $1, @vers[0,1,2],
        $vers[3]?"-":"", $vers[3], $months[@date[4]], @date[3], 1900+@date[5])/me;
  my $stringlength = 25 + 32 + length $months[@date[4]] + 2 + 6;
  die "Version string too long:  $stringlength characters." unless $stringlength < 81;
  #printf("HDF Version %d.%d Release %d%s%s, %s %d, %d\n", @vers[0,1,2],
  #        $vers[3]?"-":"", $vers[3], $months[@date[4]], @date[3], 1900+@date[5]);
  return $_[0];
}

sub usage {
  my ($prog) = $0 =~ /([^\/]+)$/;
  print STDERR <<EOF;
Usage: $prog [OPTS] [FILE]
    -i major|minor|release|annot
        Increment specified version component and set following components
        to zero.
    -s VERSION
        Set the version as specified. The version number can be embedded in
        some other string such as \"hdf4-1.1.0-pre1.tar.bz2\" or even
        \"this is HDF4 library version 1.1 release 0 (pre1)\" for convenience.
    -v
        Instead of displaying only a dotted triple version number a line such
        as \"version 1.1 release 0 (pre1)\" will be printed.
    FILE
        The name of the file that contains version information.  This is
        seldom necessary since files hfile.h, hdf/src/hfile.h,
        src/hfile.h, and ../hdf/src/hfile.h are automatically checked.
EOF
  exit 1;
}

# Parse arguments
my ($verbose, $set, $inc, $file, $rc);
my (@files) = ("hdf/src/hfile.h", "../hdf/src/hfile.h", "src/hfile.h", "hfile.h");
while ($_ = shift) {
  $_ eq "-s" && do {
    die "-s switch needs a version number\n" unless @ARGV;
    $set = shift;
    next;
  };

  $_ eq "-i" && do {
    if (@ARGV && $ARGV[0]=~/^(major|minor|release|annot)$/) {
      $inc = shift;
    } else {
      $inc = "last";
    }
    next;
  };

  $_ eq "-v" && do {
    $verbose = 1;
    next;
  };

  /^-(h|\?|-?help)$/ && usage;
  /^-/ && die "unrecognized option: $_\n";
  die "only one file name can be specified\n" if $file;
  $file = $_;
}
die "mutually exclusive options given\n" if $set && $inc;

#print "file is $file.\n";
#print "File array is ", @files;

# Determine file to use as hfile.h, README.txt,
# release_notes/RELEASE.txt, configure.in,
# and config/cmake/scripts/HDF4config.cmake.
# The paths to README.txt, release_notes/RELEASE.txt, configure.ac,
# and config/cmake/scripts/HDF4config.cmake
# files are always from the directory two levels above hfile.h.
unless ($file) {
  for (@files) {
    ($file=$_,last) if -f $_;
  }
}
#print "file is $file.\n";

die "unable to find source file $file\n" unless defined $file;
die "unable to read file: $file\n" unless -r $file;
# config/lt_vers.am - HDF4 doesn't have this at present
#my $LT_VERS = $file;
#$LT_VERS =~ s/[^\/]*$/..\/config\/lt_vers.am/;
#die "unable to read file: $LT_VERS\n" unless -r $file;
# config/cmake/scripts/HDF4config.cmake
my $HDF4CONFIGCMAKE = $file;
$HDF4CONFIGCMAKE =~ s/[^\/]*$/..\/..\/config\/cmake\/scripts\/HDF4config.cmake/;
die "unable to read file: $HDF4CONFIGCMAKE\n" unless -r $file;
my $H4_JAVA = $file;
$H4_JAVA =~ s/[^\/]*$/..\/..\/java\/src\/hdf\/hdflib\/HDFLibrary.java/;
die "unable to read file: $H4_JAVA\n" unless -r $file;
# README.txt
my $README = $file;
$README =~ s/[^\/]*$/..\/..\/README.txt/;
die "unable to read file: $README\n" unless -r $file;
# release_notes/RELEASE.txt
my $RELEASE = $file;
$RELEASE =~ s/[^\/]*$/..\/..\/release_notes\/RELEASE.txt/;
die "unable to read file: $RELEASE\n" unless -r $file;
#print $RELEASE, "\n";
# man/hdf.1
my $MANHDF1 = $file;
$MANHDF1 =~ s/[^\/]*$/..\/..\/man\/hdf.1/;
die "unable to read file: $MANHDF1\n" unless -r $file;
#print $MANHDF1, "\n";
# configure.in
my $CONFIGURE = $file;
$CONFIGURE =~ s/[^\/]*$/..\/..\/configure.ac/;
die "unable to read file: $CONFIGURE\n" unless -r $file;

# Get the current version number.
open FILE, $file or die "unable to open $file: $!\n";
my ($contents) = join "", <FILE>;
close FILE;
my (@curver) = getvers $contents;

#print "Contents:  $contents\n";

#print "curver", @curver, "\n";

# Determine the new version number.
my @newver; #new version
if ($set) {
  if ($set =~ /(\d+)\.(\d+)\.(\d+)(-([a-zA-Z]\w*))?/) {
    @newver = ($1, $2, $3, $5);
  } elsif ($set =~ /(\d+)\D+(\d+)\D+(\d+)(\s*\(([a-zA-Z]\w*)\))?\D*$/) {
    @newver = ($1, $2, $3, $5);
  } elsif ($set =~ /(\d+)\D+(\d+)\D*$/) {
    @newver = ($1, $2, 0, "");
  } elsif ($set =~ /(\d+)\D*$/) {
    @newver = ($1, 0, 0, "");
  } else {
    die "illegal version number specified: $set\n";
  }
} elsif ($inc) {
  $inc = $curver[3] eq "" ? 'release' : 'annot' if $inc eq 'last';
  if ($inc eq "major") {
    $newver[0] = $curver[0]+1;
    @newver[1,2,3] = (0,0,"");
  } elsif ($inc eq "minor") {
    $newver[0] = $curver[0];
    $newver[1] = $curver[1]+1;
    @newver[2,3] = (0,"");
  } elsif ($inc eq "release") {
    @newver[0,1] = @curver[0,1];
    $newver[2] = $curver[2]+1;
    $newver[3] = "";
  } elsif ($inc eq "annot") {
    @newver[0,1,2] = @curver[0,1,2];
    $newver[3] = $curver[3];
    $newver[3] =~ s/(\d+)\D*$/$1+1/e or
      die "Annotation \"".$newver[3]."\" cannot be incremented.\n";
  } else {
    die "unknown increment field: $inc\n";
  }
} else {
  # Nothing to do but print result
  $README = "";
  $RELEASE = "";
  $CONFIGURE = "";
  $MANHDF1 = "";
  $HDF4CONFIGCMAKE = "";
  $H4_JAVA = "";
  @newver = @curver;
}

# Note if the version increased or decreased
my $version_increased="";
# Print a warning if the version got smaller (don't check annot field)
if ($newver[0]*1000000 + $newver[1]*1000 + $newver[2] <
    $curver[0]*1000000 + $curver[1]*1000 + $curver[2]) {
  printf STDERR "Warning: version decreased from %d.%d.%d to %d.%d.%d\n",
    @curver[0,1,2], @newver[0,1,2];
}
if ($newver[0]*1000000 + $newver[1]*1000 + $newver[2] >
    $curver[0]*1000000 + $curver[1]*1000 + $curver[2]) {
  $version_increased="true";
}

# Update the version number if it changed.
if ($newver[0]!=$curver[0] ||
    $newver[1]!=$curver[1] ||
    $newver[2]!=$curver[2] ||
    $newver[3]ne$curver[3]) {
  setvers $contents, @newver or die "unable to set version\n";
  rename $file, "$file~" or die "unable to save backup file\n";
  open FILE, ">$file" or die "unable to open $file but backup saved!\n";
  print FILE $contents;
  close FILE;
}

# Update the libtool shared library version in src/Makefile.am if
# the version number has increased.
#if ($LT_VERS && $version_increased) {
#  open FILE, $LT_VERS or die "$LT_VERS: $!\n";
#  my ($contentsy) = join "", <FILE>;
#  close FILE;

#  local($_) = $contentsy;

#  my ($lt_revision) = /^LT_VERS_REVISION\s*=\s*(\d+)/m;
#  my $new_lt_revision = $lt_revision+1;
#  ($contentsy) =~ s/^(LT_VERS_REVISION\s*=\s*)\d+/$1$new_lt_revision/m;

#  open FILE, ">$LT_VERS" or die "$LT_VERS: $!\n";
#  print FILE $contentsy;
#  close FILE;
#}

# Update the config/cmake/scripts/HDF4config.cmake file
if ($HDF4CONFIGCMAKE) {
  my $data = read_file($HDF4CONFIGCMAKE);
#  my $sub_rel_ver_str = "";
  my $sub_rel_ver_str = (
     $newver[3] eq ""
     ? sprintf("\"%s\"", "")
     : sprintf("\"%s\"", "-".$newver[3].", currently under development")
     );
  my $version_string = sprintf("\"%d.%d.%d\"", @newver[0,1,2]);

  $data =~ s/set \(CTEST_SOURCE_VERSION .*\)/set \(CTEST_SOURCE_VERSION $version_string\)/;
  $data =~ s/set \(CTEST_SOURCE_VERSEXT .*\)/set \(CTEST_SOURCE_VERSEXT $sub_rel_ver_str\)/;

  write_file($HDF4CONFIGCMAKE, $data);
}

# Update the java/src/hdf/hdf5lib/HDFLibrary.java file
if ($H4_JAVA) {
  my $data = read_file($H4_JAVA);
  my $version_string = sprintf("%d.%d.%d", @newver[0,1,2]);

  $data =~ s/    public final static String JHI_VERSION = "\d*.\d*.\d*";/    public final static String JHI_VERSION = "$version_string";/;

  write_file($H4_JAVA, $data);
}

# Update the README file
if ($README) {
  open FILE, $README or die "$README: $!\n";
  my @contents = <FILE>;
  close FILE;
  $contents[0] = sprintf("HDF version %d.%d.%d%s %s",
            @newver[0,1,2],
            $newver[3] eq "" ? "" : "-".$newver[3],
            "currently under development\n");
  open FILE, ">$README" or die "$README: $!\n";
  print FILE @contents;
  close FILE;
}

# Update the release_notes/RELEASE.txt file
if ($RELEASE) {
  open FILE, $RELEASE or die "$RELEASE: $!\n";
  my @contents = <FILE>;
  close FILE;
  $contents[0] = sprintf("HDF version %d.%d.%d%s %s",
            @newver[0,1,2],
            $newver[3] eq "" ? "" : "-".$newver[3],
            "currently under development\n");
  open FILE, ">$RELEASE" or die "$RELEASE: $!\n";
  print FILE @contents;
  close FILE;
}

# Update the man/hdf.1 file
# There are currently 2 occurrences of the version string in the man/hdf.1 file.
# Since they aren't the top line of the file we search rewrite the file line by
# line, searching for the current major.minor.release version string, and replacing
# it with the new one.  In case someone changes the version string manually or it
# otherwise gets out of sync, or another match is found that should not be updated,
# we will track the changes in this file, issue an error message and exit at if
# the number of changes is different than the 2 expected.

if ($MANHDF1) {
  my $expected_updates = 2;
  my $man_hdf1_updates = 0;
  my $verstr = sprintf("%d.%d.%d", @curver[0,1,2]);
  open FILE, $MANHDF1 or die "$MANHDF1: $!\n";
  my @contents = <FILE>;
  close FILE;

  my @months = ('January', 'February', 'March', 'April', 'May', 'June', 'July',
                'August', 'September', 'October', 'November', 'December');
  my @date = (localtime(time));
  my $newverstr = sprintf("%d.%d.%d-%d", @newver[0,1,2,3]);
  my $newverstr = sprintf("%d.%d.%d%s %s",
                          @newver[0,1,2,],
                          $newver[3] eq "" ? "" : "-".$newver[3]." currently under development");
  my $newverline = sprintf(".TH HDF 1 \"%s %d\" \"THG HDF %d.%d.%d%s\"",
                           $months[@date[4]], 1900+@date[5],
                           @newver[0,1,2,],
                           $newver[3] eq "" ? "" : "-".$newver[3]);

  open FILE, ">$MANHDF1" or die "$MANHDF1: $!\n";
  foreach my $line (@contents) {
    if ($line =~ m/THG HDF $verstr/) {
      # match "THG HDF major.minor.release" in the second line, replace the line with the new line that has
      # the current month and year and the updated version.
      print FILE $newverline, "\n";
      $man_hdf1_updates += 1;
    } elsif ($line =~ m/^$verstr\s*$/ || $line =~ m/^$verstr-[a-z]{1,5}\d{1,8}\s*$/ || $line =~ m/^$verstr\scurrently under development\s*$/  || $line =~ m/^$verstr-[a-z]{1,5}\d{1,8}\scurrently under development$\s*/) {
      # match the line further down that has just the version string, and replace it with the updated version string.
      # this will match "major.minor.release" or "major.minor.release-subrelease" or  "major.minor.release currently
      # under development" or "major.minor.release-subrelease currently under development" (all followed by
      # any number of spaces), provided that the subrelease
      # string is 2-5 letters and 1-3 digits.  This should not match any line with text before or after the version.
      print FILE $newverstr, "\n";
      $man_hdf1_updates += 1;
    } else {
      print FILE $line;
    }
  }
  close FILE;
  if ($man_hdf1_updates != $expected_updates) {
    printf "ERROR: $expected_updates version updates were expected in $MANHDF1, but $man_hdf1_updates occurred.  Please check the changes to the $MANHDF1 file and correct the problem.\n";
    exit 1;
  }
}

# helper function to read the file for updating
# config/cmake/scripts/HDF4Config.cmake and
# java/src/hdf/hdf5lib/HDFLibrary.java files.
# The version string in those files is not at the top, so the string replacement
# is not for the first line, and reading/writing the entire file as one string
# facilitates the substring replacement.
sub read_file {
   my ($filename) = @_;

    open my $in, $filename or die "Could not open '$filename' for reading $!";
    local $/ = undef;
    my $all = <$in>;
    close $in;

    return $all;
}

# helper function to write the file for updating
# config/cmake/scripts/HDF4config.cmake and
# java/src/hdf/hdf5lib/HDFLibrary.java files.
sub write_file {
    my ($filename, $content) = @_;

    open my $out, ">$filename" or die "Could not open '$filename' for writing $!";;
    print $out $content;
    close $out;

    return;
}


sub gen_configure {
  my ($name, $conf) = @_;

  open FILE, $conf or die "$conf: $!\n";
  my @contents = <FILE>;
  close FILE;

  for (my $i = 0; $i < $#contents; ++$i) {
    if ($contents[$i] =~ /^AC_INIT/) {
      $contents[$i] = sprintf("AC_INIT([$name], [%d.%d.%d%s], [help\@hdfgroup.org])\n",
                              @newver[0,1,2],
                              $newver[3] eq "" ? "" : "-".$newver[3]);
      last;
    }
  }

  open FILE, ">$conf" or die "$conf: $!\n";
  print FILE @contents;
  close FILE;

  $conf =~ /^(.*?)\/?configure.ac$/;

  if ($1) {
    $rc = system("cd $1 && bin/reconfigure >/dev/null 2>/dev/null && rm -rf autom4te.cache");
  } else {
    $rc = system("bin/reconfigure >/dev/null 2>/dev/null && rm -rf autom4te.cache");
  }
  if ($rc) {
    printf("bin/reconfigure failed with exit code %d. Aborted.\n", $rc);
    exit 1;
  }
}

# Update the configure.ac files and regenerate them
gen_configure("HDF", $CONFIGURE) if $CONFIGURE;

sub gen_h5pubconf {
    my ($name, $pubconf, @vers) = @_;

    my $namelc = lc($name);
    my $nameuc = uc($name);

    open FILE, $pubconf or die "$pubconf: $!\n";
    my @contents = <FILE>;
    close FILE;

    for (my $i = 0; $i < $#contents; ++$i) {
        if ($contents[$i] =~ /\#\s*define\s+H4_PACKAGE\s+/) {
            $contents[$i] = "\#define H4_PACKAGE \"$namelc\"\n";
        } elsif ($contents[$i] =~ /\#\s*define\s+H4_PACKAGE_NAME\s+/) {
            $contents[$i] = "\#define H4_PACKAGE_NAME \"$nameuc\"\n";
        } elsif ($contents[$i] =~ /\#\s*define\s+H4_PACKAGE_STRING\s+/) {
            $contents[$i] = sprintf("\#define H4_PACKAGE_STRING \"$nameuc %d.%d.%d%s\"\n",
                                    @vers[0,1,2],
                                    $newver[3] eq "" ? "" : "-".$newver[3]);
        } elsif ($contents[$i] =~ /\#\s*define\s+H4_PACKAGE_TARNAME\s+/) {
            $contents[$i] = "\#define H4_PACKAGE_TARNAME \"$namelc\"\n";
        } elsif ($contents[$i] =~ /\#\s*define\s+H4_PACKAGE_VERSION\s+/) {
            $contents[$i] = sprintf("\#define H4_PACKAGE_VERSION \"%d.%d.%d%s\"\n",
                                    @vers[0,1,2],
                                    $newver[3] eq "" ? "" : "-".$newver[3]);
        } elsif ($contents[$i] =~ /\#\s*define\s+H4_VERSION\s+/) {
            $contents[$i] = sprintf("\#define H4_VERSION \"%d.%d.%d%s\"\n",
                                    @vers[0,1,2],
                                    $newver[3] eq "" ? "" : "-".$newver[3]);
        }
    }

    open FILE, ">$pubconf" or die "$pubconf: $!\n";
    print FILE @contents;
    close FILE;
}

# Print the new version number
if ($verbose) {
  #printf("Version %d.%d Release %d%s\n", @newver[0,1,2],
  #     $newver[3] eq "" ? "" : " (".$newver[3].")");
  printf("%s\n", $newver[4]);
} else {
  printf("%d.%d.%d%s\n", @newver[0,1,2],
    $newver[3] eq "" ? "" : "-".$newver[3]);
}

exit 0;

# Because the first line of this file looks like a Bourne shell script, we
# must tell XEmacs explicitly that this is really a perl script.
#
# Local Variables:
# mode:perl
# End:
