#!/usr/bin/env perl
# the above line will use any perl that is in your PATH. You might want to
# replace it by #!/usr/bin/perl or similar if this does not work for you.

use Getopt::Long;
Getopt::Long::Configure("prefix_pattern=--");
$result = GetOptions ("help+", "prefix=s", "yes+", "default+");
### still missing: check proper version of tar, cpio, gzip
if ( $ARGV[0] or ! $result or $opt_help) {
  print << 'EOF';
Usage: configure [options]
Options: [defaults in brackets after descriptions]
Configuration:
  --help                  print this message
  --default               do not ask questions, try to guess correct answer
  --yes                   like --default but assume yes to all questions
Directory and file names:
  --prefix=PREFIX         install lesspipe.sh in PREFIX/bin
                          [/usr/local]

configure generates both lesspipe.sh and Makefile
configure tries to find required and optional programs for lesspipe.sh
If optional programs are not found, then you can choose between
  - giving the correct location of the program if installed
  - including the code in lesspipe.sh without having the program
  - or skipping the code for the missing program.
The Makefile is of little use (copy lesspipe.sh to the install location)
EOF
  exit;
}
$opt_prefix ||= '/usr/local';
open OUT, ">Makefile";
print OUT << "EOF";
prefix = $opt_prefix

all:
	./configure --default --prefix=\$(prefix)
install:
	mkdir -p \$(prefix)/bin
	cp ./code2color ./lesspipe.sh \$(prefix)/bin
	chmod 0755 \$(prefix)/bin/lesspipe.sh
	chmod 0755 \$(prefix)/bin/code2color
clean:
	mv Makefile Makefile.old
	rm -f lesspipe.sh
EOF
close OUT;

$|=1;
# Check version of file command even before trying to create lesspipe.sh
check_file_vers();
open IN, "lesspipe.sh.in";
open OUT, ">lesspipe.sh";
$in = 1;
check_shell_vers();
while (<IN>) {
# line #ifdef prog1, prog2, ... encountered, store prog1, prog2, ... in @progs
  if ( /^#ifdef\s+(.*)/ ) {
    %rep = ();
    $_ = $1;
    chomp;
    @progs = split /,/;
# check if @progs existing and executable ($in == 1)
    $in = inpath ("Include code anyway", @progs);
# line #elif prog1, prog2, ... encountered, store prog1, prog2, ... in @progs
  } elsif (/^#elif\s+(.*)/ ) {
    $in = 1 - $in;
    next unless $in;
    %rep = ();
    $_ = $1;
    chomp;
    @progs = split /,/;
# check if @progs existing and executable ($in == 1)
    $in = inpath ("Include code anyway", @progs);
# line #endif encountered, clear list of replacement strings %rep
  } elsif (/^#else\b/ ) {
    $in = 1 - $in;
    next unless $in;
    %rep = ();
  } elsif (/^#endif\s/ ) {
    %rep = ();
# unconditionally accept all statements after #endif
    $in = 1;
  } elsif ( $in ) {
# make replacements in lines if neccessary ($in == 1)
    for $p (keys %rep) {
      s/\b$p\b/$rep{$p}/ unless /^#/;
    }
# and write out the line
    print OUT;
  }
}
close OUT;
chmod 0755, "lesspipe.sh";

sub inpath {
  my $string = shift;
  for my $prog ( @_ ) {
    $rep{$prog} = $have{$prog} if $have{$prog} and $have{$prog} =~ /^\//;
    $rep{file} = $have{gfile} if $prog eq 'gfile';
    return 1 if $have{$prog} and $have{$prog} ne 'N';
    return 0 if $have{$prog} and $have{$prog} eq 'N';
    my $ok = 0;
    print "checking $prog...";
    for ( split /:/, $ENV{PATH} ) {
      next unless m|^/|; # consider only absolute PATH elements
      $have{$prog} = "$_/$prog", last if -x "$_/$prog";
    }
    if ( $have{$prog} ) {
      print "$have{$prog}\n";
    } else {
      print "not found\n";
      my $yesno = get_answer($string, $prog);
      $have{$prog} = $yesno if ! $have{$prog} and $yesno =~ /^[yn]$/i;
      $rep{$prog} = $have{$prog} if $have{$prog} and $have{$prog} =~ /^\//;
      return 0 if $yesno !~ /^y/i;
    }
  }
  return 1;
}

sub get_answer {
  return 'y' if $opt_yes;
  return 'N' if $opt_default;
  my ($string, $prog) = @_;
  my $yesno;
  while ( $yesno !~ /^[yn]/i ) {
    print "$string [y/N or <full_path_to_$prog>] ? ";
    $yesno = <STDIN>;
    chomp $yesno;
    $yesno = 'N' if ! $yesno or $yesno =~ /^n/i;
    if ( $yesno =~ m|^/| ) {
      if ( -x $yesno ) {
	$have{$prog} = $yesno;
	$yesno = 'y';
      } else {
	print "Program $prog not found (or at least not executable)\n";
	$yesno = '';
      }
    }
  }
  return $yesno;
} 

sub check_file_vers {
  $recursion++;
# special treatment for file program
  inpath("Look for GNU gfile", 'file');
  my $rc = system "$have{file} -L ./configure >/dev/null 2>&1";
  if ( $rc ) {
    print "  found system version of file, looking for GNU file\n";
    exit unless inpath("Continue anyway", 'gfile');
    $have{file} = $have{gfile} if $have{gfile};
  }
  $rc = system "$have{file} -L ./configure >/dev/null 2>&1";
  if ( $rc ) {
    print "  found system version of file only, consider using GNU file\n";
    return if $recursion > 1;
    if ($rep{file} =~ m|^/|) {
      $have{file} = $rep{file};
      check_file_vers();
    }
  } else {
    my $vers = `$have{file} -v`;
    $vers = $1 if $vers =~ /(\d+\.\d+)/;
    if ( $vers < 3.27 ) {
      $have{file} .= ' -L';
      print <<EOF;
  found GNU file $vers, need at least 3.27 for full functionality
  (looking at unmounted media, e.g. less /dev/fd0 (floppy) will not work)
EOF
      return if $recursion > 1;
      my $yesno = 'y' if $opt_default;
      my $yesno = get_answer("Continue anyway", 'file') unless $opt_default;
      if ($rep{file} =~ m|^/|) {
        $have{file} = $rep{file};
        check_file_vers();
      }
      exit if $yesno =~ /^n/i;
    } else {
      $have{file} .= ' -L -s';
      print "  found GNU file$vers (ok)\n";
    }
  }
}

sub check_shell_vers {
# read first lines defining the shell to be used
  while (<IN>) {
    last unless /^#!/;
    push @shells, $';
  }
# remember last line read
  $line = $_;
  if ( $^O ne 'linux' ) {
    my @tmp = reverse @shells;
    @shells = @tmp;
  }
  for my $shell ( @shells ) {
    chomp $shell;
# get the basename of the shell and shell options
    my ($path, $name, $opt);
    if ( $shell =~ /(.*)\/([^\/]+)(\s.*)$/ ) {
      ($path, $name, $opt) = ($1, $2, $3);
    } else {
      ($path, $name) = ($1, $2) if $shell =~ /(.*)\/([^\/]+)\s*$/;
    }
# do we have the shell in the PATH
    my $versstr = uc $name.'_VERSION';
    $versstr = 'BASH_VERSION' if $name eq 'sh';
    my @where = grep { -x $_."/$name" } split ':', $ENV{PATH};
    $where[0] = $path if -x $path.'/'.$name; 
    my $file = $where[0].'/'.$name;
    if ( ! $where[0] or ! -x $file ) {
      print "$name not found in the PATH\n";
      push  @bad, "##!$shell\n";
      next;
    }
# get the shell version
    my $v = `$file -c \'echo \$$versstr\'`;
    chomp $v;
###    print "$file $v found in the PATH\n";
    if ( $name eq 'bash' or $name eq 'sh' ) {
      my $tst = `$file -c \'if [[ \"a\" = \"a\" ]];then true;fi 2>&1\'`;
      if ( $tst ) {
	print "skipping $shell $v, need at least 2.03\n" if $v < 2.03;
	print "skipping $shell $v, need at least 2.04\n" if $v == 2.03;
	push @bad, "##!$shell\n";
	next;
      }
    } elsif ( $v =~ /PD KSH/ ) {
      print "only $shell $v available, reduced functionality!\n"
	    if $#bad == 1; 
    }
    print OUT "#!$file$opt\n";
  }
  if ( $#bad == 2 ) {
    print "Sorry, no useable shell found, cannot create lesspipe.sh\n", @bad;
    print "You could edit lesspipe.sh.in to adjust the path to the shell(s)\n";
    exit;
  } else {
    print OUT @bad;
  }
  print OUT $line;
}
