#!/usr/bin/env perl
#!/usr/local/bin/perl
##########################################################################
# $Id=$
#
# DESCRIPTION: 
#       UPD main routine
#       (for more info, see pod at the end).
#
# AUTHORS:
#       Marc Mengel
#       Lars Rasmussen
#	Paul Russo
#       Margaret Votava
#       Don Walsh
#
#       Fermilab Computing Division
#       Batavia, IL 60510, U.S.A.                                              
#
# MODIFICATIONS:
#	02-Feb-1998, psr, first
#	10-Feb-1998, psr, second
#
##########################################################################
BEGIN {
  my $incdir;
  if ($0 = "upd") { $incdir = "../src"; }
  die "UPD_DIR is not defined ... we are quitting.\n" unless ( $ENV{UPD_DIR} );
  unshift @INC, "$ENV{UPD_DIR}/src";
}

package upd;

use strict;
use vars qw( @ISA @EXPORT );

@ISA = qw( Exporter );
@EXPORT = qw();

use Exporter ();

use cmdline;
use updgbl;
use updcmd;
use updups;
use upderr;
use upduti;

# this is for migration, we may want to rip this out later...
use updmig;

##########################################################################
# Exported variables
#

##########################################################################
# Global and local variables
#
use vars qw( %g_instance_spec $g_cmd $g_component @flavorlist @saveargs );

my $g_cmd;
my $g_component;
my %g_instance_spec = ();
my @g_flavorlist;
my $g_flavor;
my $do_colon;
my $tag;

#
#  Mainline code.
#
#  Parse the command line, validate it,
#  then execute the requested sub-command.
#

@saveargs = @ARGV;

#
# If command is a updupr command, we will skip normal processing,
# call updupr directly and quit.
#

if ( $ARGV[0] =~ m/^hi|^env|^list|^depend|^get|^exist|^flavor|^verify/ ) {

  if ($ARGV[1] eq '-?') {
	usage($ARGV[0]);
  }

  exec( 'perl', '-S', 'updupr', @ARGV );
}

cmdline_parse();

$do_colon = 0;
if ( $g_instance_spec{'flavor'} =~ m/:/ ) {
    $do_colon = 1;
    $tag = '$g_instance_spec{flavor}';
}
if ( $g_flags{opt_H} =~ m/:/ ) {
    $do_colon = 1;
    $tag = '$g_flags{opt_H}';
}

if ($do_colon) {
    upderr_log(3,"saw a colon in $tag, doing flavor list code\n");
    upderr_get(); upderr_clear();

    eval "\@flavorlist = split(':', $tag);";

    foreach $g_flavor (@flavorlist) {
        upderr_log(3,"doing flavor $g_flavor\n");
        upderr_get(); upderr_clear();

        @ARGV = @saveargs;
        %g_instance_spec = ();
	%g_flags = ();
        cmdline_parse();

        eval "$tag = \$g_flavor;";

        cmdline_validate();
        cmdline_execute();
    }
    
} else {

    cmdline_validate();
    cmdline_execute();

}

#
#  Exit to the OS with a status code.
#  Zero is the success code for UNIX.
#

exit( 0 );

##########################################################################
# Exported functions
#

##########################################################################
# Private functions
#

#-------------------------------------------------------------------------
# $status = cmdline_parse();
#
# Parse command line and extract a sub-command, an instance_spec, a set
# of flags, and optionally a component (for the "fetch" command).
#
# Input : @ARGV -- The command line arguments. 
#
# Output: $g_cmd -- Sub-command user invoked.
#         $g_instance_spec -- Product user requested.
#         $g_flags -- Options user specified.
#         $g_component -- Component user requested.
#
# Return: $status -- always true. 
#

sub cmdline_parse {

	#
	#  No arguments.
	#

	#
	#  Private variables.
	#

	my $status;		  #  Status returns from various calls.
	my @args = ();		  #  Holder for command line arguments.
	my $control;		  #  Option parsing control.
	my (@Glist,$Gval,@args2); #  -G option split parsing
	
	if ( $::ARGV[0] =~ m/^move|^(add|del|mod|rep)product|^migrate|^redotables/ ) {
	    $control = "0123cdnotf:g:h:ijnA:D:p:O:q:r:svz:G:H:Im:M:T:RU:?";  
	} elsif ( $::ARGV[0] =~ m/install/ ) {
	    $control = "0123cCdnotf:g:h:ijnO:q:r:svz:G:H:Im:M:RU:?";  
	} else {
	    $control = "0123cCdnotf:g:h:ijnq:svz:G:H:IJ:O:R?";  
	}

	#
	#  Get the command line options and arguments.
	#

	$status = cmdline_process_options( $control, 
				\@args, \%g_flags, \@::ARGV );
 
	#
	#  Get the sub-command.
	#

	$g_cmd = shift( @args );

	#
	#  Force an undefined value to an empty string
	#  in order to simplify the validation code.
	#

	if ( not defined( $g_cmd ) ) {
		$g_cmd = "";
	}

	#
	#  Get the component, if the sub-command is "update".
	#

	if ( $g_cmd eq "update" ) {
		$g_component = shift( @args );
	}

	#
	#  Force an undefined value to the empty string
	#  in order to simplify the validation code.
	#

	if ( not defined( $g_component ) ) {
		$g_component = "";
	}

	#
	#  Create a partial instance spec for the specified product.
	#

	$g_instance_spec{"product"}    = shift( @args );
	$g_instance_spec{"version"}    = shift( @args );
	$g_instance_spec{"flavor"}     = $g_flags{"opt_f"};
	$g_instance_spec{"qualifiers"} = $g_flags{"opt_q"};
	$g_instance_spec{"chain"}      = $g_flags{"opt_g"};
	$g_instance_spec{"database"}   = $g_flags{"opt_z"};

	$g_instance_spec{"chain"} = "current"     if ($g_flags{opt_c});
	$g_instance_spec{"chain"} = "old"         if ($g_flags{opt_o});
	$g_instance_spec{"chain"} = "new"         if ($g_flags{opt_n});
	$g_instance_spec{"chain"} = "development" if ($g_flags{opt_d});
	$g_instance_spec{"chain"} = "test"        if ($g_flags{opt_t});

        my $flavor;

        if ($g_flags{"opt_0"}) {
	     updups_flavor( "local", "-0", \$flavor );
             $g_instance_spec{"flavor"} = $flavor;
        }
        if ($g_flags{"opt_1"}) { 
	     updups_flavor( "local", "-1", \$flavor );
             $g_instance_spec{"flavor"} = $flavor;
        }
        if ($g_flags{"opt_2"}) { 
	     updups_flavor( "local", "-2", \$flavor );
             $g_instance_spec{"flavor"} = $flavor;
        }
        if ($g_flags{"opt_3"}) { 
	     updups_flavor( "local", "-3", \$flavor );
             $g_instance_spec{"flavor"} = $flavor;
        }


	if ( $g_cmd =~ m/^move|^(add|del|mod|rep)product|^migrate|^redotables/ ) {
	     $g_instance_spec{"authorized_nodes"} = $g_flags{"opt_A"};
	     $g_instance_spec{"origin"}           = $g_flags{"opt_D"};
	     $g_instance_spec{"table_file"}       = $g_flags{"opt_m"};
	     $g_instance_spec{"description"}      = $g_flags{"opt_p"};
	     $g_instance_spec{"table_dir"}        = $g_flags{"opt_M"};
	     $g_instance_spec{"archive_file"}     = $g_flags{"opt_T"};
	     $g_instance_spec{"ups_dir"}          = $g_flags{"opt_U"};
	     $g_instance_spec{"prod_dir"}         = $g_flags{"opt_r"};
	}
 
	#
	#  Force all undefined key values to empty strings
	#  in order to simplify the validation code.  We'll
	#  fix this later with instance_spec_fixup.
	#

	for ( keys( %g_instance_spec ) ) {
		if ( not defined( $g_instance_spec{"$_"} ) ) {
			$g_instance_spec{"$_"} = "";
		}
	}

	#
 	# set verbosity for any future calls
	#
	if ( $g_flags{"opt_v"} ) 
	   { upderr_setverbose( $g_flags{"opt_v"} ); }
	else
	   { upderr_setverbose( 0 ); }

	#
	# split -G options into a nice option hash 
	#
	$Gval = {};
        @Glist = ($g_flags{opt_G} =~ m/\s*(\S+)/g);

	upderr_log(2,"Glist is @Glist, length $#Glist\n");

	cmdline_process_options( "0123onctdf:z:g:p:q:A:D:O:", 
				\@args2, $Gval, \@Glist );
	upderr_log(2,"args2 is @args2, length $#args2\n");


        $g_flags{opt_G} = {};

        if ($#args2 >= 0) {
	    $g_flags{opt_G}->{"product"}      = shift(@args2);
	}

        if ($#args2 >= 0) {
	    $g_flags{opt_G}->{"version"}      = shift(@args2);
	}
        if ($#args2 >= 0) {
            upderr_log(0,"Warning: extra arguments @args2 in -G options ignored\n")
	}

	$g_flags{opt_G}->{"flavor"}           = $Gval->{"opt_f"};
	$g_flags{opt_G}->{"qualifiers"}       = $Gval->{"opt_q"};
	$g_flags{opt_G}->{"chain"}            = $Gval->{"opt_g"};
	$g_flags{opt_G}->{"database"}         = $Gval->{"opt_z"};
	$g_flags{opt_G}->{"description"}      = $Gval->{"opt_p"};
	$g_flags{opt_G}->{"athorized_nodes"}  = $Gval->{"opt_A"};  
	$g_flags{opt_G}->{"origin"}           = $Gval->{"opt_D"}; 
	$g_flags{opt_G}->{"ups_flags"}        = $Gval->{"opt_O"};  # capital O

	$g_flags{opt_G}->{"chain"} = "current"     if ($Gval->{opt_c});
	$g_flags{opt_G}->{"chain"} = "old"         if ($Gval->{opt_o});
	$g_flags{opt_G}->{"chain"} = "new"         if ($Gval->{opt_n});
	$g_flags{opt_G}->{"chain"} = "development" if ($Gval->{opt_d});
	$g_flags{opt_G}->{"chain"} = "test"        if ($Gval->{opt_t});

        if ($Gval->{"opt_0"}) {				    # number zero
	     updups_flavor( "local", "-0", \$flavor );
             $g_flags{opt_G}->{"flavor"} = $flavor;
        }
        if ($Gval->{"opt_1"}) { 
	     updups_flavor( "local", "-1", \$flavor );
             $g_flags{opt_G}->{"flavor"} = $flavor;
        }
        if ($Gval->{"opt_2"}) { 
	     updups_flavor( "local", "-2", \$flavor );
             $g_flags{opt_G}->{"flavor"} = $flavor;
        }
        if ($Gval->{"opt_3"}) { 
	     updups_flavor( "local", "-3", \$flavor );
             $g_flags{opt_G}->{"flavor"} = $flavor;
        }

	my $key;
        foreach $key (keys(%{$g_flags{opt_G}})) {
            if ($g_flags{opt_G}->{$key} eq '') {
 	       delete $g_flags{opt_G}->{$key};
	    }
        }

	upderr_log(2,"option -G instance spec:\n");
	upduti_print_instance_spec(2,$g_flags{opt_G});
        
	#
	#  Return to our caller with status success.
	#

	return( 1 );

}

#-------------------------------------------------------------------------
# $status = cmdline_validate();
#
# Validate the command line.
#
# Input : $g_cmd -- Sub-command specified.
#         $g_instance_spec -- Product specified.
#         $g_flags -- Option flags specified.
#         $g_component -- Component specified (for "fetch" only).
#
# Output: Aborts if command line not valid.  Instance spec is
#         filled out completely with data from server.
#
# Return: Always true.
#

sub cmdline_validate {

	#
	#  No arguments.
	#

	#
	#  Private variables.
	#

	my $status;				#  Return status from
						#  various routines.

	my %allowed_components = (		#  Valid components for fetch
		"table_file" => 1,
		"ups_dir" => 1,
		"table_file:ups_dir" => 1,
		"ups_dir:table_file" => 1,
	);

#  Information to request
#  from the server in order
#  to fill out an instance
#  spec completely.
	my @find_components = qw(
		_upd_overlay	
		archive_file
		chain	
		database
		description
		flavor
		prod_dir
		prod_dir_prefix
		product
		qualifiers
		table_dir
		table_file
		ups_dir
		version
	);

	#
	#  Validate sub-command.
	#

	if (	    ( $g_cmd ne "install" )
		and ( $g_cmd ne "update"  )
		and ( $g_cmd ne "fetch"   )
		and ( $g_cmd ne "addproduct" 	     )
		and ( $g_cmd ne "repproduct" 	     )
		and ( $g_cmd ne "cloneproduct" 	     )
		and ( $g_cmd ne "modproduct" 	     )
		and ( $g_cmd ne "delproduct" 	     )
		and ( $g_cmd ne "move_archive_file"  )
		and ( $g_cmd ne "move_table_file"    )
		and ( $g_cmd ne "move_ups_dir"  )
		and ( $g_cmd ne "migrate"    )
		and ( $g_cmd ne "redotables"    )
	) {
		usage('');
	}
	#
	#  Remote host defaults to $g_default_remote_node, defined in
	#  upsgbl.pm
	#

	if ( not defined( $g_flags{"opt_h"} ) ) {
	   $g_flags{"opt_h"} = $g_default_remote_node;
	   upderr_log(2,"Defaulting distribution node to $g_flags{opt_h}\n");
	}

	#
	#  If no flavors specified, default to a search-list
	#  based on the local system's OS flavor.
	#

	if ( !defined( $g_flags{"opt_H"} )) {

		my $flavor;

		#
		#  Ask ups on the local node for the OS flavor.
		#

		$status = updups_flavor( "local", "-3", \$flavor );

		if ( not $status ) {
		   upderr_get(); upderr_clear();
		   die( "Unable to get local flavor, stopped" );
		}

		#
		#  Use the local OS flavor as the -H option.
		#

		$g_flags{"opt_H"} = $flavor;

	}


        if ( $g_cmd =~ /^move|^(mod|add|del|rep)product|^migrate|^redotables/ ) {

	     # most of the checks are  wrong for move commands...

	     instance_spec_fixup( \%g_instance_spec );
	     return 1;
	}

	if ( $g_flags{"opt_help"} ) {
		usage($g_cmd);
	}

	#
	#  A product must be specified.
	#


	if ( $g_instance_spec{"product"} eq "" ) {
		die( "You must specify a product, stopped" );
	}

	#
	#  Both version and chain is illegal.
	#

	if (	    ( $g_instance_spec{"version"} ne "" )
		and ( $g_instance_spec{"chain"}   ne "" )
	) {
		die( "You cannot specify both a version and a chain, stopped" );
	}

	#
	#  If no version or chain specified, default chain to "current". 
	#

	if (	    ( $g_instance_spec{"version"} eq "" )
		and ( $g_instance_spec{"chain"}   eq "" )
	) {
		$g_instance_spec{"chain"} = "current";
		$g_flags{"opt_g"} = "current";
	}

	#
	#  Insert a "foundby" key into the partial instance spec.
	#

	if ( $g_instance_spec{"version"} eq "" ) {
		$g_instance_spec{"foundby"} = $g_instance_spec{"chain"};
	}
	else {
		$g_instance_spec{"foundby"} = "";
	}

	#
	#  If sub-command is "update", validate $g_component.
	#

	if ( $g_cmd eq "update" ) {
		if ( not exists( $allowed_components{"$g_component"} ) ) {
			die( "Invalid component specified, stopped" );
		}
	}

	#
	#  Enforce semantics on instance spec.
	#

	instance_spec_fixup( \%g_instance_spec );

	#
	#  Fill out the instance spec fully from server info.
	#

	#
	#  N.B.:  updups_find has an infelicity in its specification:
	#         it will never overwrite an entry in the passed
	#         instance spec, so we may not get all the information
	#         we ask for.  Sigh, ...
	#

	$status = updups_find(	$g_flags{"opt_h"},
				\%g_instance_spec,
				@find_components
	);
        upduti_print_instance_spec(3,\%g_instance_spec);

	if ( not $status ) {
           upderr_get(); upderr_clear();
	   die( "Could not find specified product on server, stopped" );
	}

	#
	#  Delete any garbage entries returned from updups_find, and it
	#  does return garbage!
	#

	instance_spec_fixup( \%g_instance_spec );

	#
	#  And return to our caller with a success status.
	#
	
	return( 1 );

}

#-------------------------------------------------------------------------
# $status = cmdline_execute();
#
# Call the handling routine for the sub-command specified. 
#
# Input : $g_cmd -- Sub-command specified by user.  One of: "install",
#                   "update", or "fetch".
#
# Output: Whatever sub-command does. 
#
# Return: Status returned by sub-command.
#

sub cmdline_execute {

	#
	#  No arguments.
	#

	#
	#  Private variables.
	#

	my $status;			#  Return status from various routines.
	my $error_string;		#  Accumulated error text.

	#
	#  Handle the -? option.
	#

	if ( $g_flags{"opt_help"} ) {

		#
		#  User has asked for help,
		#  give him some.
		#

		usage($g_cmd);

		#
		#  Return to the OS with a success exit status.
		#

		exit( 0 );

	}

	#
	#  Use the specified sub-command to decide
	#  which worker routine to call.
	#
	my $cmd;

	for ( $g_cmd ) {

		#
		#  Install sub-command.
		#

		/^install$/	and do {
			$cmd = $&;
			$status = updcmd_install( \%g_instance_spec );
			last;
		};

		#
		#  Update sub-command.
		#

		/^update$/	and do {
			$cmd = $&;
			$status = updcmd_update( \%g_instance_spec,$g_component );
			last;
		};

		#
		#  Fetch sub-command.
		#

		/^fetch$/	and do {
			$cmd = $&;
			$status = updcmd_fetch( \%g_instance_spec );
			last;
		};

		#
		# redotables command for old/new kits migration
		#
		/^redotables$/ and do {
			$cmd = $&;
			$status = updmig_redotables( \%g_instance_spec );
			last;
		};
		#
		# migrate command for old/new kits migration
		#
		/^migrate$/ and do {
			$cmd = $&;
			$status = updmig_migrate( \%g_instance_spec );
			last;
		};
		#
		# addproduct and its server node callback commands
		#
		/^(rep|add|mod)product$/ and do {
			if ( !defined($::ENV{USER}) ) {
			    if (defined($::ENV{USERNAME})) {
				$::ENV{USER} = $::ENV{USERNAME};
			    } else {
				upderr_log(0,"error: USER environment variable not set, needed for authentication\n");
				$status = 0;
				last;
			    }
			}
			$cmd = $&;
			my $add_inst_spec;
			$add_inst_spec=\%g_instance_spec;
			if ($cmd eq 'repproduct') {
			    my $del_inst_spec;
			    $del_inst_spec = {%$add_inst_spec};
			    delete $del_inst_spec->{archive_file};
			    delete $del_inst_spec->{table_file};
			    delete $del_inst_spec->{table_dir};
			    delete $del_inst_spec->{ups_dir};
			    upderr_log(2,"add spec:");
 			    upduti_print_instance_spec(2, $add_inst_spec);
			    upderr_log(2,"del spec:");
 			    upduti_print_instance_spec(2, $del_inst_spec);
                            updcmd_delproduct( $del_inst_spec );
                        }
			$status = updcmd_add_mod_product( $add_inst_spec , ($cmd eq 'modproduct'));
			last;
		};
		/^(cloneproduct)$/ and do {
			$cmd = $&;
			$status = updcmd_cloneproduct( \%g_instance_spec );
			last;
		};
		/^(delproduct)$/ and do {
			$cmd = $&;
			$status = updcmd_delproduct( \%g_instance_spec );
			last;
		};
		/^(move_table_file)$/ and do {
			$cmd = $&;
			$status = updcmd_move_table_file( \%g_instance_spec );
			last;
		};
		/^(move_ups_dir)$/ and do {
			$cmd = $&;
			$status = updcmd_move_ups_dir( \%g_instance_spec );
			last;
		};
		/^(move_archive_file)$/ and do {
			$cmd = $1;
			$status = updcmd_move_archive_file( \%g_instance_spec );
			last;
		};


		#
		#  Unknown command.
		#
		$status = 0;
		$cmd = "unknown command";
		usage('');
	}
	if ( not $status ) {
	    upderr_log(0, "upd $cmd failed.");
	    upderr_get(); upderr_clear();
	    if (!$g_flags{opt_i}) {
	        exit 1;
	    }
	}

	#
	#  Return to caller with success status.
	#

        upderr_get(); upderr_clear();
	return( 1 );

}

#-------------------------------------------------------------------------
# $status = flags_print( \%hash );
#
# Dump the contents of a flags hash.
#
# Input : $flags -- Reference to a flags hash.
#
# Output: Contents of flags hash dumped to screen.
#
# Return: $status -- Always true.
#

sub flags_print {

	#
	#  Passed arguments.
	#

	my $flags = shift();

	#
	#  Private variables.
	#

	#
	#  Check passed arguments.
	#

	if (	   not defined( $flags )
		or not ( ref( $flags ) eq "HASH" )
	) {
		die( "Invalid parameters!, stopped" );
	}

	#
	#  Print values for each key, in sorted key order.
	#

	for ( sort( keys( %$flags ) ) ) {
		print "\$flags->{$_} = \"$flags->{$_}\"\n";
	}

	#
	#  Return to caller with success status.
	#

	return( 1 );

}

#-------------------------------------------------------------------------
# $status = instance_spec_print( \%instance_spec );
#
# Dump the contents of an instance_spec hash.
#
# Input : $instance_spec -- Reference to an instance_spec hash.
#
# Output: Contents of instance_spec hash dumped to screen.
#
# Return: $status -- Always true.
#

sub instance_spec_print {
	
	#
	#  Passed arguments.
	#

	my $spec = shift();

	#
	#  Private variables.
	#

	#
	#  Check passed arguments.
	#

	if (	   not defined( $spec )
		or not ( ref( $spec ) eq "HASH" )
	) {

		die( "Invalid parameters!, stopped" );
	}

	#
	#  Print key values in sorted key order.
	#

	for ( sort( keys( %$spec ) ) ) {
		print "\$instance_spec->{\"$_\"} = \"$spec->{$_}\"\n";
	}

	#
	#  Return to caller with success status.
	#

	return( 1 );

}

#-------------------------------------------------------------------------
# $status = instance_spec_fixup( \%instance_spec );
#
# Remove undefined vals and empty vals from an instance_spec.
#
# Input : $instance_spec -- Reference to an instance_spec hash.
#
# Output: Instance spec is pruned and stripped, presence of
#         qualifiers key is enforced.
#
# Return: $status -- Always true.
#

sub instance_spec_fixup {

	#
	#  Passed arguments.
	#

	my $spec = shift();

	#
	#  Private variables.
	#

	#
	#  Check passed arguments.
	#

	if (	   not defined( $spec )
		or not ( ref( $spec ) eq "HASH" )
	) {

		die( "Invalid parameters!, stopped" );
	}

	#
	#  Remove empty strings and undefined values
	#  from the instance spec.
	#

	instance_spec_prune( $spec );

	#
	#  N.B.:  The spec has changed.  We must now enforce the presence
	#         of the qualifiers key.  If it is not present it must
	#         entered as an empty string.
	#

	if ( not exists( $spec->{"qualifiers"} ) ) {
		$spec->{"qualifiers"} = "";
	}

	#
	#  N.B.:  The spec has changed.  We must now enforce the presence
	#         of the foundby key.  If it is not present, then the
	#         product instance was found by version which needs to be
        #         signalled using an empty string.
	#

	if ( not exists( $spec->{"foundby"} ) ) {
		$spec->{"foundby"} = "";
	}

	#
	#  Strip any outer double quotes from values.
	#

	instance_spec_strip( $spec );

	#
	#  Return to caller with success status.
	#

	return( 1 );

}

#-------------------------------------------------------------------------
# $status = instance_spec_prune( \%instance_spec );
#
# Remove undefined vals and empty vals from an instance_spec.
#
# Input : $instance_spec -- Reference to an instance_spec hash.
#
# Output: Keys with undefined values and keys with empty string values
#         are removed from the instance_spec hash.
#
# Return: $status -- Always true.
#

sub instance_spec_prune {

	#
	#  Passed arguments.
	#

	my $spec = shift();

	#
	#  Private variables.
	#

	#
	#  Check passed arguments.
	#

	if (	   not defined( $spec )
		or not ( ref( $spec ) eq "HASH" )
	) {

		die( "Invalid parameters!, stopped" );
	}

	for ( keys( %$spec ) ) {

		if (	   ( not defined( $spec->{"$_"} ) )
			or ( $spec->{"$_"} eq "" )
		) {
			delete( $spec->{"$_"} );
		}

	}

	#
	#  Return to caller with success status.
	#

	return( 1 );

}

#-------------------------------------------------------------------------
# $status = instance_spec_strip( \%instance_spec );
#
# Remove any outer double quotes from instance spec values.
#
# Input : $instance_spec -- Reference to an instance_spec hash.
#
# Output: Outer double quotes are stripped from instance_spec values.
#
# Return: $status -- Always true.
#

sub instance_spec_strip {

	#
	#  Passed arguments.
	#

	my $spec = shift();

	#
	#  Private variables.
	#

	#
	#  Check passed arguments.
	#

	if (	   not defined( $spec )
		or not ( ref( $spec ) eq "HASH" )
	) {

		die( "Invalid parameters!, stopped" );
	}

	#
	#  Loop through keys of instance spec.  If the key's value
	#  is surrounded by double quotes, remove them.
	#

	for ( keys( %$spec ) ) {

		if ( defined( $spec->{"$_"} ) ) {
			$spec->{"$_"} =~ s/^"(.*)"$/$1/;
		}

	}

	#
	#  Return to caller with success status.
	#

	return( 1 );

}

#-------------------------------------------------------------------------
# $status = usage();
#
# Print synopsis help.
#
# Input : None.
#
# Output: A short synopsis of upd syntax is presented to the user.
#
# Return: $status -- Always true.
#

sub usage {
        my ($helppat) = @_;

	#
	#  No arguments.
	#

	#
	#  Private variables.
	#

	#
	#  Return to caller with success status.
	#

	print "usage:\n";

	if ("list" =~ /$helppat/) {
	   print "  upd list [-h host] [-g chain] [-q quals] [-f flavor] \\\n\t[-K keywords] [-a] [product] [vers]\n";
        }
	if ("depend" =~ /$helppat/) {
	   print "  upd depend [-h host] [-g chain] [-q quals] [-f flavor]\\\n\t [-K keywords] product [vers]\n";
        }
	if ("fetch" =~ /$helppat/) {
	   print "  upd fetch [-h host] [-g chain] [-q quals] [-f flavor] product\\\n\t [vers] [-J filename]\n";
        }
	if ("install" =~ /$helppat/) {
	   print "  upd install [-h host] [-q quals] [-f flavor] product [vers]\\\n\t[-G \"[-f flavor] [-g chain] [-q quals] [product [vers]]\"] \n";
	}
	if ("update" =~ /$helppat/) {
	   print "  upd update component_name [-h host] [-q quals] [-f flavor] product [vers]\n";
	}
	if ("repproduct" =~ /$helppat/) {
	   print "  upd repproduct [-h host] [-q quals] [-f flavor] product [vers] \\\n\t[-T tarfile] [-M table_dir] [-m table_file] [-U ups_dir] [-g chain]\n";
	}
	if ("addproduct" =~ /$helppat/) {
	   print "  upd addproduct [-h host]  [-q quals][-f flavor] product [vers] \\\n\t[-T tarfile] [-M table_dir] [-m table_file] [-U ups_dir] [-g chain]\n";
	}
	if ("cloneproduct" =~ /$helppat/) {
	   print "  upd cloneproduct [-h host] [-q quals] [-f flavor] product [vers] \\\n\t-G \"[-f flavor] [-g chain] [-q quals] [product [vers]]\"\n";
	}
	if ("modproduct" =~ /$helppat/) {
	   print "  upd modproduct [-h host] [-q quals] [-f flavor] product [vers] \\\n\t[-M table_dir] [-m table_file] [-U ups_dir] [-g chain]\n";
	}
	if ("delproduct" =~ /$helppat/) {
	   print "  upd delproduct [-h host] [-q quals] [-f flavor] product [vers]\n";
	}

	exit($helppat eq '');
}

1;

__END__

=head1 NAME

upd - blah blah

=head1 SYNOPSIS

<use it this way>

=head1 DESCRIPTION

<description>

=head1 BUGS

<bugs>

=cut
