=head1 NAME

CFX5::PrintConfig - Display the current configuration

=head1 SYNOPSIS

This package provides functions for displaying the current
configuration to stdout, for example when -v is passed to a script.

=cut

package CFX5::PrintConfig;

use strict;

use vars qw($CVSVersion);
$CVSVersion='$Id$ ';

use Exporter;
use vars qw(@ISA @EXPORT_OK %EXPORT_TAGS);
@ISA=qw(Exporter);
@EXPORT_OK=qw(show_vars show_vars_by_verbosity);

use CFX5::Config qw(query_conf getconf getconf_default export_conf);
use CFX5::Output qw(:all);

=head1 VARIABLE LAYOUT

This module is in two parts. The first part sets up a couple of hashes
for setting categories for the various different variables ("Build
Variables", "Strange Things Needed for NT", that sort of thing), which
the functions in the second part use to display the configuration
records in various ways.

Note that most of the things in this first half are not in general
accessible from other packages.

=head2 %VarSection

A hash, indexed by either the variable name (if it exists), or the
I<calcfunction> (see the C<%calcfuntion> hash for more details) if the
variable is not in the hash. The value for each key is the name of a
section in which to put the variables in the listing. The name of the
section is encoded as a leading flag letter, followed by a title, the
flag letter being one of:

=over

=item B<A>lways show this variable

=item B<B>uild environment only; not normally relevant to end-users

=item B<I>nternal variable, not relevant to end-users.

=item B<H>idden variable, only show if really asked for it!

=back

Note that by default when a user asks for a listing, they get all B<A>
and B<B> variables if they are set; these two flags are only
differentiated by what they do when asked for a I<full> listing.

This hash is indexed at compile-time from (you guessed it) a hash
constructed the other way round, so each key is the name of a section,
and points to the list of records/calcfunctions to include in the
section. 

=head2 %SectionVar

This holds the same information as C<%VarSection>, but indexed by
variable rather than by section.

=head2 @VarSections

An ordered list of the sections as they appear; this is the order they
should be displayed in.

=cut

use vars qw(%VarSection %SectionVar @VarSections $MaxVarLen);

BEGIN {
  # define this as a list, so it stays ordered. It's still constructed
  # of key/value pairs, though, so we have to do a little extra work
  # to read it.
  # SEAN PEARSON adding CFX_PRE_RULES_ORIG CFX_PRE_RULES_APPLICATION CFX_PRE_RULES_EXTRA
  $MaxVarLen=0;
  my @sv=(
	  'AConfiguration File Locations'
	  => [qw(
		 CFX_SITEFILE
		 CFX_USERFILE
		 CFX_STDFILE
		 CFX_RELEASE_FILE
		 CFX_EPILOG
		 CFX_PROFILE_DIR
		 CFX_USER_CONFIG_DIR
		)],

	  'AProduct Information'
	  => [qw(
		 CFXREVISION
		 CFXBUILDID
		 CFXBUILDID_MAJOR_MINOR
		 CFXBUILDID_NOSEP_MAJOR_MINOR
		 CFXBASERELEASE
		 ANSYSCFXRELEASE
		 CFX5BUILDNUM
		 ANSYSINSTALLROOT
		 ICEMINSTALLROOT
		)],

	  'ASystem Architecture'
	  => [qw(
		 CFX_FORCE_WOW64
		 CFX_OS
		 CFX5OS
		 CFX5ARCH
		 CFX5_HOST_ARCH
		 CFX5_SOLVER_ARCH
		 ASC_MACH
		 MSC_M
		 MSCv7_M
		 CFX5ASCMACH
		 LM_ARCH
		 CFX5DEBUG
		 CFX5_ARCH_ATTRS
		 CFX5_ARCH_TYPE
		)],

	  'AProduct Directories'
	  => [qw(
		 CFX_ROOT
		 CFX5ROOT
		 CFX_CMD_DIR
		 CFX_CONFIG_DIR
		 CFX_DATA_DIR
		 CFX_EXTERNALS_DIR
		 CFX_CUSTOM_DATA_DIR 
		 CFX_EG_DIR
		 CFX_ICON_DIR
		 CFX_INCLUDE_DIR
		 CFX5_MATERIALS_DIR
		 CFX5BINDIR
		 CFX5EXECDIR
		 CFX5EXECTOP
		 CFX5LIBDIR
		 CFX5LIBTOP
		 CFX5OBJDIR
		 CFX5OBJTOP
		 CFX5SCCS
		 CFX5TESTDIR
		 CFX_TCLPROCS
		 CFX_TEST_ROOT
		 CFX_TOOLS_ROOT
		)],

	  'ASettings for the ANSYS CFX Launcher'
	  => [qw(
		 CFX_USER_CONFIG_DIR
		 CFX_USE_PROJECT
		)],

	  'ASettings for ANSYS CFX Command Language'
	  => [qw(
		 CFX5_CCL_LIBS
		 CFX5_CCL_LIBSDIR
		 CFX5_CCL_RULESDIR
		 CFX5_CCL_RULES
		 CFX5_CCL_PARSER
		 CFX5_CCL_LIB
		 CFX5_CCL_PARSER_PACKAGE
		 CFX5_TT_FILE
		)],

	  'ASettings for ANSYS CFX Pre- and Post-processing'
	  => [qw(
		 CFX_QT_DIR
		 CFX_QT_VERSION
		 CFX_QT_OS
		 CFX_QT_LIBDIR
		 QT_PLUGIN_PATH
		 CUE_GRAPHICS
		 CFX_MESA_LIBDIR
		 CUE_BINEXT
		 CUE_ISLOCAL
		 CUE_DIRSUFF
		 CUE_ROOT
		 CUE_DIR
		 CUE_DIR_UNIX
		 CUE_POSTENGINE_DIR
		 CUE_POSTGUI_DIR
		 CUE_PREENGINE_DIR
		 CUE_PREGUI_DIR
		 CUE_TGENGINE_DIR
		 CUE_TGGUI_DIR
		 CUE_CHARTER_DIR
		 CUE_CHARTVIEWER_DIR
		 CUE_IMAGECONVERT_DIR
		 CUE_EXEC_ROOT
		 CUE_EXE_DIR
		 CUE_LIB_DIR
		 CUE_POSTGUI_EXE
		 CUE_POSTENGINE_EXE
		 CUE_PREGUI_EXE
		 CUE_PREENGINE_EXE
		 CUE_TGGUI_EXE
		 CUE_TGENGINE_EXE
		 CUE_CALCLIB_DIR
		 CUE_PERL_PRELIBSDIR
		 CUE_PERL_POSTLIBSDIR
		 CUE_PERL_TGLIBSDIR
		 CFX_POST_LIBSDIR
		 CFX_POST_LIBS
		 CFX_PRE_LIBSDIR
		 CFX_PRE_LIBS
		 CFX_TG_LIBSDIR
		 CFX_TG_LIBS
		 CFX_PRE_RULES_CCL
		 CFX_PRE_RULES_CHANGE
		 CFX_PRE_PHYSICS_LIB
		 CFX_PRE_GUI_LIB
		 CFX_PRE_RULES_ORIG 
		 CFX_PRE_RULES_APPLICATION 
		 CFX_PRE_RULES_EXTRA
		 CFX_PRE_RULES_CCL_DEFAULT
		 CFX_PRE_RULES_CHANGE_DEFAULT
		 CFX_PRE_PHYSICS_LIB_DEFAULT
		 CFX_PRE_GUI_LIB_DEFAULT
		 CFX_PRE_INIT_DEFAULT
		 CUE_VIEWER_DIR
		 CUE_VIEWER_EXE
		 CUE_BROWSER_ROOT
		 CUE_BROWSER_DIR
		 CUE_BROWSER_EXE
		 CUE_LOCAL_DATA_DIR
		 CUE_GLOBAL_DATA_DIR
		 CUE_PIXMAP_DIR
		 CFX_CUE_ICONDIR
		 CUE_DICT
		 PLPLOT_LIB
		 TASC_FONT_DIR
		 TASC_FONTS
		 CFX5_DIR
		 CUEOS
		 CUE_TG_STRAIGHT_PASSAGE
		 CUE_NO_DEBUG_OUT
		 MED_ROOT
		 ICEM_ACN
		 MED_LIB
		 TASCUTS_DIR
		 TASCUTS_BINDIR
		 TASCUTS_UTILITY
		)],

	  'ACommands for ANSYS CFX "Tools" menu'
	  => [qw(
		 CFX5BROWSER
		 CFX5EDITOR
		 CFX5XTERM
		)],

	  'ASettings for the ANSYS CFX Solver'
	  => [qw(
		 CFX5_PARALLEL_MODE
		 CFX5_IBMMPI_VERSION
		 CFX5_IBMMPI_DIR
		 CFX5_IMPI_VERSION
		 CFX5_IMPI_DIR
		 CFX5_HOSTS_CCL
		 CFX5_START_METHODS_CCL
		 CFX5_HOSTS_FILE
		 CFX5_PLATFORMINFO_CMDS
		 CFX5_PROFILE_OUTPUT_SIZE
		 CFX5_REACTIONS_DIR
		 CFX_SOLVER_OUTPUT_FILE
		 CFX_SOLVER_EXE
		 CFX_SOLVER_EXEC
		 CFX_SOLVER_EXEC_ARCH
		 CFX5_STANDARD_IO
		 P4_GLOBMEMSIZE
		 PVM_ROOT
		 PVM_VERSION
		 PVM_ARCH
		)],

	  'ASettings for the ANSYS CFX Solver Manager'
	  => [qw(
		 CFX_MANAGER_DIR
		 CFX_MANAGER_ROOT
		 CFX_MANAGER_EXEC
		 CFX_WISH
		 CFX_TCLSH
		 DEFFILE
		 TK_VERSION
		 TK_LIBRARY
		 TCL_VERSION
		 TCL_LIBRARY
		 CUESM_DIR
		 CUESM_SCRIPT_PATH
		 CUESM_ETC_DIR
		 CUESM_RESOURCE_DIR
		 CUESM_HELP_DIR
		 CUESM_BROWSER_DIR
		 CFX5_CUESM_CCL_LIBS
		)],

	  'ASettings for CFX on-line help'
	  => [qw(
		 CFX_DOC_DIR
		 CFX_HELP_DIR
		 CFX_NO_AUTO_HELP
		 CFX_HELP_SUPRESS_SERVER
		 CFX_HELP_RPC_PROP
		 CFX_HELP_WAS_STARTED_FOR
		 CFX_PLAPI_EXEC
		 FMARCH
		 FMHOME
		 FMVERSION
		)],

	  'BCompile/Link options'
	  => [qw(
		 CFX5FC
		 CFX5FFLAGS
		 CFX5FOPT
		 CFX5LD
		 CFX5LDFLAGS
		 CFX5LDLIBS
		)],

	  'BMacros for make'
	  => [qw(
		 CFX5AR
		 CFX5ARFLAGS
		 CFX5CC
		 CFX5CDBG
		 CFX5CFLAGS
		 CFX5COPT
		 CFX5CPP
		 CFX5CPPFLAGS
		 CFX5CSTD
		 CFX5ETDIR
		 CFX5ET2C
		 CFX5ETLIBS
		 CFX5FDBG
		 CFX5FSTD
		 CFX5GET
		 CFX5GFLAGS
		 CFX5MAKEDIR
		 CFX5MK
		 CFX5MKFLAGS
		 CFX5PROF
		 CFX5SRCDIR
		 CFXDOC
		)],

	  'APath settings'
	  => [qw(
		 HOME
		 PATH
		 LD_LIBRARY_PATH
		 LD_LIBRARYN32_PATH
		 LD_LIBRARY64_PATH
		 LD_LIBRARY_PATH_64
		 LIBPATH
		 SHLIB_PATH
		 CFX_WIN32_DRIVE_LIST
		 CFX5_RESTORE_LIBPATH
		 )],

	  'ALicensing settings'
	  => [qw(
		 ANSYSLIC_DIR
		 CFX_ANSYSLIC_DIR
		 CFX_LICENSING_ROOT
		 CFX_LICENSE_ROOT
		 CFX_LICENSING_MODE
		 CFX_LICINT_MODE
		 CFX_LICMAN_EXEC
		 LM_LICENSE_FILE
		 LM_ROOT
		 CFX_LICENSE_FILE
		 CFX5_LICENSE_KEY
		 LSHOST
		 LSFORCEHOST
		 SLMDEFAULTDIR
		 LM_PROJECT
		 CFX_EXPIRY_DESC
		 CFX_EXPIRY_FILE
		 CFX_EXPIRY_TIME
		)],

	  'AOther settings'
	  => [qw(
		 CFX5AWK
		 CFX5LNS
		 CFX5MONO
		 CFX_JAVA_VERSION
		 CLASSPATH
		 CFX_HELP_DIR
		 CFX_HELP_JARDIR
		 CFX5PERL
		 CFX5RSH
		 CFX5VERSION
		 CFX_FORMAT
		 CFX_HOST
		 CFX_FULLHOST
		 CFX_MOTIF_LOOK
		 CFX5_MPEG_ENCODE_EXE
		 CFX_RECORD_CALCULATE
		 CFX_SMALL_SCREEN
		 CFX_USER
		 DISPLAY
		 LANG
		 CFX_AWP_LOCALE
		 OPENWINHOME
		 PERL_VERSION
		 SGI_ABI
		 TMPDIR
		 TEMP
		 TMP
		 XENVIRONMENT
		 __SGI_NO_REMOTE_GL
		)],

	  'IInternal Variables'
	  => [qw(
		 CFX_AVOID_SHELL_COMMANDS
		 CFX_HELP_RPC_PROP
		 CFX_RUN_WISH_INTERACTIVELY
		 CFX_BUILD_ORIG_TMPDIR
		 CFX_RUNNING_SCRIPTS
		 CFX_SUPPRESS_README
		 CFX5_SUPPRESS_README
		 CFX5VERSION_W
		 CFX5ROOT_FORCE
		 arch_name
		 debug_suff
		 dir_sep
		 ld_path_var
		 path_sep
		 perl_arch
		 sig_name
		 windows_nt
		)],
	 );

  while (scalar(@sv) > 0) {
    my $sect=shift @sv;
    my $rvlist=shift @sv;

    unless (exists $SectionVar{$sect}) {
      push @VarSections, $sect;
      $SectionVar{$sect}=[];
    }

    my $v;
    for $v (@$rvlist) {
      $MaxVarLen=length($v)
	if length($v) > $MaxVarLen;
      push @{$SectionVar{$sect}},$v;
      $VarSection{$v} = $sect;
    }
  }
}

=head1 DISPLAY FUNCTIONS

These functions display various sets of the available data in
different ways. The names of the functions do follow some sort of
pattern. 

=head2 show_vars

  show_vars($setonly,$flag_unset,$pad);

Display to the screen in a pretty human-readable form (which is also,
incidentally, useful for cutting and pasting into config files) those
configuration variables which have been requested.

If $setonly is true, only those variables which have been set before
this function was called are shown; otherwise, all known variables are
calculated if necessary, and then displayed. If $flag_unset is true,
variables which are not set are also shown.

C<$pad> is the expected maximum variable length; it has a reasonable
default if not passed (or passed as undef), and normally should not be
used.

=cut

sub show_vars {
  my ($setonly,$flag_unset,$maxlen)=@_;

  $setonly=defined $setonly ? $setonly : 0;
  $flag_unset=defined $flag_unset ? $flag_unset : 0;
  $maxlen=defined $maxlen ? $maxlen : $MaxVarLen+1;
  
  my $s;

  # we will show any missing ones later
  my %localenv=%ENV;

  for $s (@VarSections) {
    # split on an empty RE => between the first two chars?
    my ($flag,$name)=split(//,$s,2);
    my @lines;
    my $havedata=0;
    if ($flag eq "A" or $flag eq "B") {
      my $v;
      my $nameprinted=0;
      for $v (@{$SectionVar{$s}}) {
	my $val;
	if ($setonly) {
	  $val=query_conf($v);
	} else {
	  $val=getconf($v);
	}
	if (defined $val or $flag_unset) {
	  # don't display a section title unless there's something in it
	  unless ($nameprinted) {
	    push @lines, "\n$name\n\n";
	    $nameprinted=1;
	  }
	}

	if (defined $val) {
	  my $vp=$v;
	  # this line puts "*" before exported variables; comment it
	  # out to disable this.
	  if (exists $ENV{$v}) {
	    if ($ENV{$v} ne $val) {
	      _warn("$v has a different value in the current environment");
	    }
	    $vp="*".$v;
	  }

	  # now display the variable value, if it has one
	  my $pad=$maxlen-length($vp);
	  $pad=0 if ($pad<0);
	  push @lines, " "x$pad, $vp, "=\"", $val, "\"\n";
	  $havedata++;
	} elsif ($flag_unset) {
	  my $pad=$maxlen-length($v);
	  $pad=0 if ($pad<0);
	  push @lines, " "x$pad, $v, " (unset)\n";
	}	  
	delete $localenv{$v};
      }
    } else {
      # if we're explicitly not displaying these things, then delete
      # them anyway
      for my $v (@{$SectionVar{$s}}) {
	delete $localenv{$v};
      }
    }
    if ($havedata) {
      _print @lines;
    }
  }

  {
    my @lines;
    push @lines, "\nOther Environment Variables\n\n";
    for my $v (sort keys %localenv) {
      my $val;
      if ($setonly) {
	$val=query_conf($v);
      } else {
	$val=getconf($v);
      }

      if (defined $val) {
	my $vp=$v;
	# this line puts "*" before exported variables; comment it
	# out to disable this.
	if (exists $ENV{$v}) {
	  if ($ENV{$v} ne $val) {
	    _warn("$v has a different value in the current environment");
	  }
	  $vp="*".$v;
	}
	
	# now display the variable value, if it has one
	my $pad=$maxlen-length($vp);
	$pad=0 if ($pad<0);
	push @lines, " "x$pad, $vp, "=\"", $val, "\"\n";
      } elsif ($flag_unset) {
	my $pad=$maxlen-length($v);
	$pad=0 if ($pad<0);
	push @lines, " "x$pad, $v, " (unset)\n";
      }	  
    }
    _print @lines;
  }
  
  _print "\n";
}

=head2 show_vars_by_verbosity

  CFX5::PrintConfig::show_vars_by_verbosity();

Call C<show_vars>, with arguments depending on the current level of
verbosity: 

=over

=item none

Does nothing.

=item "info" (C<-v>)

Displays currently-set variables. (1,0)

=item "moreinfo" (C<-v -v>)

Displays all variables, but does not set any which are currently
unset. (1,1)

=item "debug"

(This is set if C<$ENV{CFX_OUTPUT}> contains C<debug>; it is not
implied by the C<-debug> switch). Set and display all variables,
whether required for this script or not. (0,1)

=back

This function should be called as late as possible in the script, so
it shows correctly which variables are set; in particular, it should
be called after variables are exported with C<export_conf>.

=cut

sub show_vars_by_verbosity {
  my ($so,$fu);

  $fu=0;
  $so=1 if (CFX5::Output::query_verbosity('info'));
  $fu=1 if (CFX5::Output::query_verbosity('moreinfo')
	    or CFX5::Output::query_verbosity('debug'));
  $so=0 if (CFX5::Output::query_verbosity('debug'));

  show_vars($so,$fu) if defined $so;

  1;
}

1;
