#! /bin/sh

#****************************************************************************
#
#                             BLDLVLCK
#
#  This perl script checks the user's system for the required levels of
#  software needed to properly build Hercules from the source repository.
#
#  Updated 11 DEC 2021
#
#****************************************************************************

PERLPROG=perl

which ${PERLPROG} > /dev/null

if [ "$?" -ne 0 -a -x /usr/local/bin/perl ] ; then
PERLPROG=/usr/local/bin/perl
fi

exec ${PERLPROG} -w -x $0 "$@"

#! perl -w

use strict;

#    Facility, required level, special flag, download URL

my @req = qw(
     autoconf    2.64   0  http://www.gnu.org/directory/autoconf.html
     automake    1.9    0  http://www.gnu.org/directory/automake.html
     bash        3.2    0  http://www.gnu.org/directory/bash.html
     cmake       3.2    0  https://cmake.org
     flex        2.5    0  http://www.gnu.org/directory/flex.html
     gawk        3.0    0  http://www.gnu.org/directory/gawk.html
     gcc         6.2.0  1  http://www.gnu.org/directory/gcc.html
     grep        1      0  http://www.gnu.org/directory/grep.html
     ld          2.22   0  http://www.gnu.org/directory/binutils.html
     libtool     2.4.6  1  https://sdl-hercules-390.github.io/html/hercinst.html
     libltdl     1      1  https://sdl-hercules-390.github.io/html/hercinst.html
     m4          1.4.6  0  http://www.gnu.org/directory/GNU/gnum4.html
     make        3.79   0  http://www.gnu.org/directory/make.html
     perl        5.6    1  http://www.gnu.org/directory/perl/html
     sed         3.02   0  http://www.gnu.org/directory/sed.html
);

my $gcc_i686_required = "6.3.0";
my $m4_netbsd_required = "20150116";

my $msg;
my $instversion;

sayintro();

my $machine = `uname -m`;
print "Machine architecture is $machine\n";

for (my $i = 0; $i < @req; $i += 4) {
  my $facility = $req[$i];
  my $level = $req[$i+1];
  my $special = $req[$i+2];

  if ($facility eq 'sed') {
    if ($^O eq 'darwin') {
      print "Apple/Darwin ==> sed changed to gsed!\n" ;
      $facility = 'gsed';
    }

    if ($^O eq 'freebsd') {
      print "FreeBSD ==> custom version parsing!\n" ;
      $special = 1;
    }

    if ($^O eq 'netbsd') {
      print "NetBSD ==> custom version parsing!\n" ;
      $special = 1;
    }
  }

  if ($facility eq 'ld') {
    if ($^O eq 'darwin') {
      # print "Apple/Darwin ==> custom version parsing!\n" ;
      $special = 1;
    }
  }

  if ($facility eq 'm4') {
    if ($^O eq 'darwin') {
      # print "Apple/Darwin ==> custom version parsing!\n" ;
      $special = 1;
    }

    if ($^O eq 'freebsd') {
      print "FreeBSD ==> custom version parsing!\n" ;
      $special = 1;
    }

    if ($^O eq 'netbsd') {
      print "NetBSD ==> custom version parsing!\n" ;
      $special = 1;
      $level = $m4_netbsd_required;
    }
  }

  if ($facility eq 'make') {
    if ($^O eq 'freebsd') {
      print "FreeBSD ==> substituting gmake for make.\n" ;
      # $special = 1;
      $facility = 'gmake';
    }
  }

  my $url = $req[$i+3];
  if ($special) {
    weird($facility, $level, $url);
  } else {
    if (present($facility, $url)) {
      my @resp = `$facility --version`;
      chomp $resp[0];
      $instversion = getvers($resp[0]);
      $msg = ckvers($level, $instversion);
      print "$msg\t$facility requires $level, found $instversion\n";
      print "\tURL: $url\n" if $msg eq 'UPGRADE';
    }
  }
  print "\n";
}

exit 0;

sub weird {
  my ($facility, $level, $url) = @_;

  if ($facility eq 'perl') {
    if (present($facility, $url)) {
      my $instversion = getvers($^V);
      my $msg = ckvers($level, $instversion);
      print "$msg\t$facility requires $level, found $instversion\n";
      print "\tURL: $url\n" if $msg eq 'UPGRADE';
    }
    return;
  }

  if ($facility eq 'libltdl') {
      my $status = system("echo '#include \"ltdl.h\"' | cc \$CPPFLAGS \$CFLAGS -dI -E -x c - >/dev/null 2>&1");

      if ($? == -1) {
        print "compiler couldn't execute: $!\n";
      } elsif ($? & 127) {
        printf "compiler process died with signal %d, %s coredump\n",
          ($? & 127), ($? & 128) ? 'with' : 'without';
      } else {
        #printf "compiler process exited with value %d\n", $? >> 8;

        if ($? >> 8 == 0) {
          #print "return status 0 - include file was found\n";
          print "OK\tltdl.h required include file, found\n";
        } else {
          print "ltdl.h required include file, NOT found.";
          print "\tURL: $url\n";
        }
      }

      #print "\t$resp[0]\n";
      #chomp $resp[0];
    return;
  }

  if ($facility eq 'ld') {
    if (present($facility, $url)) {
      if ($^O eq 'darwin') {
        print "Apple/Darwin ==> ld has no version info!\n" ;
        $msg = "OK";
        print "$msg\t$facility required, found\n";
      } else {
        my @resp = `ld --version`;
        #print "\t$resp[0]\n";
        chomp $resp[0];
        my $instversion = getvers($resp[0]);
        my $msg = ckvers($level, $instversion);
        print "$msg\t$facility requires $level, found $instversion\n";
        print "\tURL: $url\n" if $msg eq 'UPGRADE';
      }
    }
    return;
  }

  if ($facility eq 'libtool') {
    if (present($facility, $url)) {
      if ($^O eq 'darwin') {
        print "Apple/Darwin ==> libtool has no version info!\n" ;
        $msg = "OK";
        print "$msg\t$facility required, found\n";
      } else {
        my @resp = `libtool --version`;
        #print "\t$resp[0]\n";
        chomp $resp[0];
        my $instversion = getvers($resp[0]);
        my $msg = ckvers($level, $instversion);
        print "$msg\t$facility requires $level, found $instversion\n";
        print "\tURL: $url\n" if $msg eq 'UPGRADE';
      }
    }
    return;
  }

  if ($facility eq 'm4') {      # m4 --version: GNU m4 1.4o
    if (present($facility, $url)) {
      my $resp;
      if ($^O eq 'freebsd') {
        $resp = `m4 --version 2>&1`;
      } elsif ($^O eq 'netbsd') {
        $resp = `m4 --version 2>&1`;
      } else {
        $resp = `m4 --version`;
      }

      chomp $resp;
      my $msg = 'HUH?   ';
      my $instversion = "DUNNO";

      if ($resp =~ /GNU [mM]4 (\d+.\d+.\d+)/) {
        $instversion = '';
        $instversion = $1 if defined $1;
        $instversion = "$1.$2" if defined $1 && defined $2;
        $instversion = "$1.$2.$3" if defined $1 && defined $2 && defined $3;
        $msg = ckvers($level, $instversion);
      }

      if ($^O eq 'freebsd' && $resp =~ /m4: illegal/) {
        $msg = 'm4';
        print "m4\t$facility version is unavailable on FreeBSD\n";
      }

      if ($^O eq 'netbsd' && $resp =~ /m4 version (\d{8})/) {
        $instversion = '';
        $instversion = $1 if defined $1;
        $msg = ckvers($level, $instversion);
      }

      print "$msg\t$facility requires $level, found $instversion\n";
      print "\tURL: $url\n" if $msg eq 'UPGRADE';
    }
    return;
  }


  if ($facility eq 'gcc') {
    my $cc = $ENV{"CC"} || "gcc";

    if (present($cc, $url)) {
      my @resp;
      if ($^O eq 'netbsd') {
        @resp = `$facility -dumpversion`;
      } elsif ($^O eq 'darwin') {
        @resp = `$facility --version 2>/dev/null`;
      } else {
        @resp = `$facility --version`;
      }
      chomp $resp[0];
      $instversion = getvers($resp[0]);

      if ($machine =~ /i686/) {
          $msg = ckvers($gcc_i686_required, $instversion);
          print "$msg\t$facility (32-bit) requires $gcc_i686_required, found $instversion\n";
      } else {
          $msg = ckvers($level, $instversion);
          print "$msg\t$facility requires $level, found $cc $instversion\n";
      }
      print "\tURL: $url\n" if $msg eq 'UPGRADE';
    }

    return;
  }

  if ($facility eq 'sed') {
    if (present($facility, $url)) {
      if ($^O eq 'freebsd') {
        my @resp = `sed --version 2>&1`;
        chomp $resp[0];
        my $msg = 'HUH?   ';
        my $instversion = "DUNNO";

        print "\t$resp[0]\n";
        if ($resp[0] =~ /sed: unknown option/) {
          # print "netbsd: \n";
        }

        print "$msg\t$facility requires $level, found $instversion\n";
        print "\tURL: $url\n" if $msg eq 'UPGRADE';
      }

      if ($^O eq 'netbsd') {
        my @resp = `sed --version 2>&1`;
        chomp $resp[0];
        my $msg = 'HUH?   ';
        my $instversion = "DUNNO";

        print "\t$resp[0]\n";
        if ($resp[0] =~ /sed: unknown option/) {
          # print "netbsd: \n";
        }

        print "$msg\t$facility requires $level, found $instversion\n";
        print "\tURL: $url\n" if $msg eq 'UPGRADE';
      }
    }
    return;
  }

  print "ERROR $facility flagged as special, not found\n";
}

sub getvers {
  my $resp = $_[0];
  my $vers;
  if ($resp =~ /(\d+).(\d+).(\d+)/) {
    $vers = "$1.$2.$3";
    return $vers;
  }
  if ($resp =~ /(\d+).(\d+)/) {
    $vers = "$1.$2";
    return $vers;
  }
  print "HUH?\n";
}

sub ckvers {
  my ($reqvers, $instvers) = @_;
  my @rv = split /\./, $reqvers;
  my @iv = split /\./, $instvers;
  for (my $i = 0; $i < @rv; $i++) {
    if ( (exists $rv[$i])
      && (exists $iv[$i])
      && ($iv[$i] > $rv[$i]) ) {
      return 'OK';
    }
    if ( (exists $rv[$i])
      && (exists $iv[$i])
      && ($iv[$i] < $rv[$i]) ) {
      return 'UPGRADE';
    }
  }
  return 'OK';
}

sub sayintro {
    print "This utility will check the level of various utilities needed to build\n";
    print "hercules. Checking is done against versions that are KNOWN to work.\n";
    print "This doesn't mean a build will NOT succeed with older versions\n";
    print "of the utilities, but will give a hint as to what package may need\n";
    print "an upgrade if the build ever fails with some odd reason.\n\n\n";
}

sub present {
  my ($facility, $url) = @_;
  my @present = `which $facility 2>/dev/null`;
  if (! @present) {
    print "INSTALL\t$facility not found\n";
    print "\tURL: $url\n";
  }
  return scalar @present;
}
