#! perl -w

##
## Name
##
## cfx5info
##
## Purpose
## 
## Gather and display information about CFX-5 and the local machine.
##
## Synopsis
##
#S cfx5info [-inst] [-full] [-system] [-config] [-help] [-cmds]
#S          [-subsets] [-verbose]
#S cfx5info [-host] [-os] [-arch] [-whereis <cmd>] [-reltype]
##
## []  denotes an optional argument. 
## |   separates mutually exclusive arguments. 
## ... following an argument indicates that it may be repeated.
## <>  denotes that substitution of a suitable value is required. All other
##     arguments are keywords, some of which may have a short form.
##
## Arguments:
##
#A -full
##    Displays a full report on the installation and configuration of
##    CFX-5, suitable for emailing to the CFX Support desk. This
##    includes the output of the -inst and -system options.
##
#A -help
##    Shows help on the cfx5info command.
##
#A -inst
##    Displays information about the installation directory, and
##    available versions of CFX-5. This is the default if no arguments 
##    are passed.
##
#A -system
##    Displays information about the system cfx5info is running on.
##
#A -cmds
##    Prints the location of some common commands, if they can be
##    found on the PATH.
##
#A -config
##    If any site-specific or user-specific configuration files are in
##    use, this option will display their locations and contents.
##
#A -subsets
##    Show information about which subsets are installed.  This option
##    is valid on UNIX only.
##
#A -patches
##    Show information for all installed patches.
## 
#A -host
##    Display the current host name.
##
#A -host-addr <host>
##    Looks up the named host in the network database, and displays
##    some information about it.
##
#A -os
##    Display the short architecture string for this machine.
##
#A -arch
##    Display the long architecture string for this machine.
##
#A -reltype
##    Display the release type, which will be "development",
##    "prerelease" or "release".
##
#A -whereis <cmd>
##    Displays all available versions of <cmd>, as found on the
##    PATH. This option can be repeated.
##
#A -v
#A -verbose
##    This option will cause cfx5info to print more information about
##    environment variables which are currently set.
##
#U ****************************************************************************
#U *                                                                          *
#U *     The following features are supported only within CFX and are not     *
#U *     shown by the -help option when the command is run elsewhere.         *
#U *                                                                          *
#U ****************************************************************************
#U
#U Unsupported Features:        
#U
#U Developers can use cfx5info to interrogate the CFX-5 environment
#U variables from external scripts. All the "interrogation options"
#U below echo the requested information to stdout, by default without
#U any extra information; so you can do 
#U      CFX5LIBDIR=`cfx5info -libdir`
#U Alternatively, see the -sh-set and -csh-set switches.
#U
#U Arguments:
#U
#U -sh-set
#U -csh-set
#U -ksh-set
#U     Rather than just printing the value of the variable, emit the
#U     required shell code to set the variable in the environment. If
#U     you are setting a lot of variables, you can do something like
#U          eval `cfx5info -sh-set -libdir -objdir -version`
#U     and save yourself a little time.  THESE ARE NOT CURRENTLY
#U     IMPLEMENTED!
#U
#U Interrogation options
#U
#U Option                    Variable           Alias(es)
#U
#U -arch                     CFX5_HOST_ARCH
#U -os                       CFX5OS
#U     The CFX-5 architecture (long) string and OS (short) string for
#U     the current machine. 
#U
#U -host
#U     The current host name 
#U
#U -license		     LM_LICENSE_FILE
#U -lic-root                 CFX_LICENSE_ROOT
#U     Licensing information.  (Possibly read from the registry on NT)
#U
#U -rootdir                  CFX_ROOT           (CFX5ROOT)
#U -cmddir                   CFX_CMD_DIR        (CFX5BINDIR)
#U -egdir                    CFX_EG_DIR
#U -configdir                CFX_CONFIG_DIR
#U -datadir                  CFX_DATA_DIR
#U -execdir                  CFX5EXECDIR
#U -objdir                   CFX5OBJDIR
#U -libdir                   CFX5LIBDIR
#U     Some of the CFX-5 directories.
#U
#U -version                  CFXBUILDID
#U     The current version of CFX-5.
#U

#===============================================================================
# Configuration of this script
#===============================================================================

#
# these are the commands to show when -cmds is passed
#
use vars qw(@ImportantCommands);
BEGIN {
  if ($^O eq 'MSWin32') {
    @ImportantCommands = 
      qw(
	 cfx5
	 exceed
	 frame
	 frameviewer
	 lpr
	 rsh
	 cmd
	);
  } else {
    @ImportantCommands =
      qw(
	 cfx5
	 lpr
	 rsh
	 sh
	 ksh
	);
  }
}

#
# define these once-and-for-all
#
use vars qw(%ConfVarArgs);
BEGIN {
  %ConfVarArgs =
    (
     '-host'      => 'CFX_HOST',
     '-os'        => 'CFX5OS',
     '-cfxos'     => 'CFX_OS',
     '-arch'      => 'CFX5_HOST_ARCH',
     '-reltype'   => 'CFX5RELTYPE',
     '-version'   => 'CFXBUILDID',
     '-rootdir'   => 'CFX5ROOT',
     '-cmddir'    => 'CFX_CMD_DIR',
     '-egdir'     => 'CFX_EG_DIR',
     '-configdir' => 'CFX_CONFIG_DIR',
     '-datadir'   => 'CFX_DATA_DIR',
     '-execdir'   => 'CFX5EXECDIR',
     '-objdir'    => 'CFX5OBJDIR',
     '-libdir'    => 'CFX5LIBDIR',
     '-license'   => 'LM_LICENSE_FILE',
     '-lic-root'  => 'CFX_LICENSE_ROOT',
    );
}

#===============================================================================
# The script itself

# get the standard CFX-5 library directory
BEGIN {
  if ($0 =~ m!^([a-z]:)?[\\/]!i) {
    # it's an absolute path, use it as-is
    (my $nd=$0) =~ s!(perllib[\\/])?[^\\/]*$!!i;
    unshift @INC, "$nd/perllib";
  } else {
    # wrap this in an eval, and if it fails, pray ... for example,
    # this can fail on Windows if we're running off a share.
    eval {
      require FindBin;
      FindBin->import();
      (my $dir=$FindBin::Bin) =~ s![\\/]perllib!!g;
      unshift @INC, "$dir/perllib";
      my $dummy=$FindBin::Bin; # kill used only once warning
    };
    warn $@ if $@;
  }
  if (defined $ENV{CFX_LOCAL_PERLLIB}) {
     unshift @INC, $ENV{CFX_LOCAL_PERLLIB};
  }

}

use vars qw($CVSVersion);
sub BEGIN {
  $CVSVersion='@(#) $Id$\n';
}

use strict;

use CFX5::Output qw(:all);
use CFX5::Config qw(%Config export_conf);
use CFX5::PrintConfig;

use CFX5::CmdLine qw(:util parse_cmdline);

use CFX5::LIST;

BEGIN {
  require Config;
  if ( $Config::Config{archname} =~ m/MSWin32/ ) { 
    require CFX5::Win32::SysInfo;
  }
}

use CFX5::PathManip qw(join_file findbin_by_path);
use CFX5::FileOps qw(glob_suffix);

use CFX5::FrameServ;		# used by DefaultConfig to find Frame if included

use CFX5::Commands qw(get_cmd_output do_cmd);

use CFX5::PatchInfo;

_debug "About to init ...";

use CFX5::Init;
CFX5::Init::init();

_debug "Init done.";


#
# parse the argument list.
#
my (@opt,$verbose,@whereis,@host,@var);
parse_cmdline
  ( \@ARGV,
    '-NoConsole' => \&handle_std_arg,
    '-win32-dlg' => \&handle_std_arg,
    '-no-inherit' => \&handle_std_arg,
    '-help'      => sub {
      _debug "About to read config ...";
      CFX5::Config::read_config();
      _debug "Finished reading config";
      handle_std_arg(@_);
    },
    '-h'         => "-help",
    '-inst'      => \@opt,
    '-full'      => \@opt,
    '-system'    => \@opt,
    '-host'      => \@opt,
    '-os'        => \@opt,
    '-arch'      => \@opt,
    '-reltype'   => \@opt,
    '-subsets'   => \@opt,
    '-patches'   => \@opt,
    '-config'    => \@opt,
    '-v'         => sub {
      push @opt, $_[0] ;
      CFX5::Output::set_verbosity("info");
    },
    '-verbose'   => '-v',
    '-cmds'      => \@opt,
    '-whereis+'  => \@whereis,
    '-host-addr+' => \@host,
    '-var+'      => \@var,
    # include all the arguments pertaining to config variables
    # automatically
    map { $_ => \@opt } keys %ConfVarArgs,
  );

exit_if_error();

# default mode
push @opt, '-inst' unless scalar(@opt)+scalar(@whereis)+scalar(@host)+scalar(@var) > 0;

# we explicitly set this so the read_config is quiet, and then unset
# it later if necessary.
use vars qw($old_suppress_readme);
$old_suppress_readme=$Config{CFX_SUPPRESS_README};
$Config{CFX_SUPPRESS_README}=1;

# for some of the easier things, we allow running without a HOME
# directory set, to make running from rsh on Windows easier.  This is
# obviously not ideal, but it's about as close as we can get AFAICT.
{
  my $needhome=0;
  for my $o (@opt) {
    unless (exists $ConfVarArgs{$o}) {
      $needhome=1;
    }
  }
  unless ($needhome) {
    $Config{allow_unset_home}=1;
  }
}

#
# read the configuration
#
_debug "About to read config ...";
CFX5::Config::read_config();
_debug "Finished reading config";

#
# do we need to show the README?
#
if (!$old_suppress_readme) {
  my $showit=0;
  for my $o (@opt) {
    unless (exists $ConfVarArgs{$o}) {
      $showit=1;
    }
  }
  if ($showit) {
    $Config{CFX_SUPPRESS_README}=$old_suppress_readme;
    CFX5::Config::show_readme();
  }
}

if (CFX5::Output::query_verbosity('info')) {
  # re-find the license file stuff from the registry on NT
  CFX5::LIST::license_file();
}

#
# now do our thing.
#
{
  my %optf =
    (
     '-inst'      => \&s_inst,
     '-full'      => \&s_full,
     '-system'    => \&s_system,
     '-subsets'   => \&s_subsets,
     '-patches'   => \&s_patches,
     '-config'    => \&s_config,
     '-v'         => \&s_v,
     '-verbose'   => \&s_v,
     '-cmds'      => \&s_cmds,
    );

  for my $c (@whereis) {
    print join("\n",s_whereis($c),'');
  }

  for my $h (@host) {
    print host_info($h);
  }

  for my $o (@opt) {
    if (exists $ConfVarArgs{$o}) {
      s_showvar($ConfVarArgs{$o});
    } else {
      &{$optf{$o}}($o);
    }
  }

  for my $v (@var) {
    s_showvar($v);
  }
}

exit_if_error();
exit(0);

sub s_showvar {
  my $v=shift;
  my $val=$Config{$v};
  if (defined $val) {
    print "$val\n";
  } else {
    print STDERR "Unable to calculate $v\n";
  }
}

sub s_whereis {
  my $c=shift;
  my @rv=findbin_by_path($c,1);
  if ($rv[0] eq '.') {
    return ("$c not found");
  } else {
    return @rv;
  }
}

sub s_inst {
  _trace "Showing install info";

  print <<"!EOM!";
                   CFX-5 Installation Information
		   ******************************

The CFX installation directory \"<CFXROOT>\" is $Config{CFX_ROOT}

!EOM!

  # the available versions check only really makes sense for the style
  # where all versions are in the same place!

  if ($Config{CFX_DIR_STYLE} eq 'complete') {
    print "The current version is $Config{CFXBUILDID}. Available versions:\n";

    my @all=glob_suffix(join_file($Config{CFX_ROOT},'bin',''));
    my @ver=grep(m/^5\.[0-9]/,@all);

    print "      ",join("\n      ",@ver),"\n\n";

    my @other=grep(m/^[0-46-9]\.[0-9]/,@all);
    if (@other) {
      print "The following versions of other CFX products are installed\n";
      print "in the same tree:\n";
      print "      ",join("\n      ",@other),"\n\n";
    }
  }
}

sub s_v {
  CFX5::PrintConfig::show_vars(0,1);
}

sub s_cmds {
  for my $c (@ImportantCommands) {
    my @l=s_whereis($c);
    if (scalar(@l) > 0) {
      print $c,"\n";
      print "  ",join("\n  ",@l),"\n";
    } else {
      print $c, " not found\n";
    }
  }
}

sub s_system {
  if (defined &CFX5::Win32::SysInfo::get_info_string) {
    print CFX5::Win32::SysInfo::get_info_string();
  } else {
    my $instcmd=join_file($Config{CFX5BINDIR},'show_system');
    do_cmd($instcmd);
  }
  print "\n";

  # do a gethostbyname() on the local host name
  print host_info($Config{CFX_HOST});

  print CFX5::LIST::license_info_text();
}

sub host_info {
  my $host=shift;

  my $str;
  $?=0;
  my ($name,$aliases,$addrtype,$length,@addrs)=gethostbyname($host);
  if (defined $name) {
    $str .= "Host database information for host $name:\n";
    if (defined $aliases and $aliases) { $str .= "  (alias $aliases)\n"; }
    if (@addrs) { 
      $str .= "  IP address(es): ";
      for my $a (@addrs) {
        $str .= join('.',unpack('C4',$a)) . " ";
      }
      $str .= "\n";
    } else {
      $str .= "  No known IP addresses!\n";
    }
  } else {
    if ($?) {
      $str .= "No host information is available for host $host (gethostbyname failed: error $?)\n";
    } else {
      $str .= "No host information is available for host $host (gethostbyname failed)\n";
    }
  }
  $str .= "\n";

  $str;
}

sub s_config {
  if (defined $Config{CFX_SITEFILE}) {
    print "\nSite configuration file $Config{CFX_SITEFILE}:\n\n";
    local *FILE;
    if (open FILE, "<$Config{CFX_SITEFILE}") {
      while (defined (my $l=<FILE>)) {
	print $l;
      }
      close FILE;
    } else {
      print "Unable to read file: $!\n";
    }
  } else {
    print "\nNo site configuration file.\n";
  }
  if (defined $Config{CFX_USERFILE}) {
    print "\nUser configuration file $Config{CFX_USERFILE}:\n\n";
    local *FILE;
    if (open FILE, "<$Config{CFX_USERFILE}") {
      while (defined (my $l=<FILE>)) {
	print $l;
      }
      close FILE;
    } else {
      print "Unable to read file: $!\n";
    }
  } else {
    print "\nNo user configuration file.\n";
  }
  1;
}

sub s_subsets {
  if ($Config{windows_nt}) {
    print "\nSubset information is not available on Windows NT\n\n";
  } else {
    my $instcmd=join_file($Config{CFX5ROOT},'install','show_subsets');
    if (-f $instcmd) {
      my $info=get_cmd_output($instcmd, '-report');
      print $info;
    } else {
      print "No information about installed subsets is available as the CFX-5\nInstallation Tools are not correctly installed.\n\n";
    }
  }
}

sub s_patches {
  my $patchinfo = CFX5::PatchInfo->new();
  if ($patchinfo->is_nonempty()) {
    my @patchtext = $patchinfo->get();
    printf "\n%s\n\n", join("\n ", @patchtext);
  } else {
    print "\nNo Point Releases or Patches known.\n";
  }
}

sub s_full {
  s_inst();

  print <<"!EOM!";

                         Variable Settings
			 =================


!EOM!
  s_v();

  print <<"!EOM!";

                        Configuration Files
		        ===================


!EOM!
  s_config();

  print <<"!EOM!";

                      Common Command Locations
		      ========================


!EOM!
  s_cmds();

  print <<"!EOM!";

                         Patches Installed
		         =================


!EOM!
  s_patches();

  print <<"!EOM!";


                         System Information
			 ==================

!EOM!
  s_system();
}
