# Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved. 
#
#    NAME
#      asmcmdtmpl - ASM CoMmanD line interface TEMPLATE operations
#
#    DESCRIPTION
#      This module contains the code for ASMCMD/ASM template-related
#      operations, such as listing the contents of v$asm_template.
#
#    NOTES
#      usage: asmcmdcore [-p] [command]
#
#    MODIFIED  (MM/DD/YY)
#    moreddy    01/13/11 - Backport moreddy_bug-8667038 from main
#    amitroy    04/21/10 - BUG 8933243 - USE DIFFERENT CHARACTER IN ASMCMD TO
#                          "HIDE COLUMN DETAILS" INSTEAD OF -H
#    pvenkatr   03/31/10 - Syntax, description, example - all from XML
#    moreddy    03/22/10 - Adding more tracing
#    moreddy    01/18/10 - Adding tracing messages
#    pvenkatr   09/03/09 - Help message from xml file
#    sanselva   06/17/09 - correct check for --primary and --secondary
#    sanselva   04/06/09 - ASMCMD long options and consistency
#    heyuen     10/14/08 - use dynamic modules
#    heyuen     07/28/08 - use command properties array
#    heyuen     05/27/08 - remove entry_number field
#    heyuen     04/15/08 - rename zones to regions
#    heyuen     07/23/07 - creation
#
#############################################################################
#
############################ Functions List #################################
# asmcmdtmpl_init
# asmcmdtmpl_process_cmd 
# asmcmdtmpl_process_lstmpl
# asmcmdtmpl_process_mktmpl
# asmcmdtmpl_process_chtmpl
# asmcmdtmpl_process_rmtmpl
# asmcmdtmpl_is_cmd 
# asmcmdtmpl_is_no_instance_cmd 
# asmcmdtmpl_parse_int_args
# asmcmdtmpl_syntax_error 
# asmcmdtmpl_process_help 
# asmcmdtmpl_get_asmcmd_cmds 
#############################################################################

package asmcmdtmpl;
require Exporter;
our @ISA    = qw(Exporter);
our @EXPORT = qw(asmcmdtmpl_init
                 %asmcmdtmpl_cmds
                );

use strict;
use Getopt::Long qw(:config no_ignore_case bundling);
use asmcmdglobal;
use asmcmdshare;

use List::Util qw[min max];

####################### ASMCMDTMPL Global Constants ######################
# ASMCMD Column Header Names:
# Below are the names of the column headers for lstmpl.
our (%asmcmdtmpl_lstmpl_header) = ('inst_id'      , 'Inst_Id',
                                   'group_name'   , 'Group_Name',
                                   'name'         , 'Name',
                                   'stripe'       , 'Stripe',
                                   'system'       , 'Sys',
                                   'redundancy'   , 'Redund',
                                   'group_number' , 'Group_Num',
                                   'primary_region' , 'PriReg',
                                   'mirror_region'  , 'MirrReg'
                                  );

our (%asmcmdtmpl_cmds) = (lstmpl => {wildcard    => 'True',
                                     no_instance => 'True',
                                     flags       =>  {'l'=>'longListing',
                                                      'G=s'=>'diskGroup',
                                                      'suppressheader'=>
                                                     'suppressHeaders'}
                                                    },
                          mktmpl => {no_instance => 'True',
                                     flags       =>  {'G=s'=>'diskGroup',
                                                      'striping=s'=>
                                                     'diskStriping',
                                                      'redundancy=s'=>
                                                     'redundancyType',
                                                      'primary=s'=>
                                                     'primaryRegion',
                                                      'secondary=s'=>
                                                     'secondaryRegion'}
                                                    },
                          chtmpl => {no_instance => 'True',
                                     flags       =>  {'G=s'=>'diskGroup',
                                                      'striping=s'=>
                                                     'diskStriping',
                                                      'redundancy=s'=>
                                                     'redundancyType',
                                                      'primary=s'=>
                                                     'primaryRegion',
                                                      'secondary=s'=>
                                                     'secondaryRegion'}
                                                    },

                          rmtmpl => {no_instance => 'True',
                                     flags       =>  {'G=s'=>'diskGroup'}
                                                    }
                         );

####################### ASMCMDTMPL Global Variables ######################

sub is_asmcmd
{
  return 1;
}

########
# NAME
#   asmcmdtmpl_init
#
# DESCRIPTION
#   This function initializes the asmcmdtmpl module.  For now it simply 
#   registers its callbacks with the asmcmdglobal module.
#
# PARAMETERS
#   None
#
# RETURNS
#   Null
#
# NOTES
#   Only asmcmdcore_main() calls this routine.
########
sub init
{
  push (@asmcmdglobal_command_callbacks, \&asmcmdtmpl_process_cmd);
  push (@asmcmdglobal_help_callbacks, \&asmcmdtmpl_process_help);
  push (@asmcmdglobal_command_list_callbacks, \&asmcmdtmpl_get_asmcmd_cmds);
  push (@asmcmdglobal_is_command_callbacks, \&asmcmdtmpl_is_cmd);
  push (@asmcmdglobal_is_wildcard_callbacks, \&asmcmdtmpl_is_wildcard_cmd);
  push (@asmcmdglobal_syntax_error_callbacks, \&asmcmdtmpl_syntax_error);
  push (@asmcmdglobal_no_instance_callbacks, \&asmcmdtmpl_is_no_instance_cmd);
  %asmcmdglobal_cmds = (%asmcmdglobal_cmds, %asmcmdtmpl_cmds);

  #Perform ASMCMD consistency check if enabled
  if($asmcmdglobal_hash{'consistchk'} eq 'y')
  {
     if(!asmcmdshare_check_option_consistency(%asmcmdtmpl_cmds))
     {
       exit 1;
     }
  }

}


########
# NAME
#   asmcmdtmpl_process_cmd
#
# DESCRIPTION
#   This routine calls the appropriate routine to process the command 
#   specified by $asmcmdglobal_hash{'cmd'}.
#
# PARAMETERS
#   dbh       (IN) - initialized database handle, must be non-null.
#
# RETURNS
#   1 if command is found in the asmcmdtmpl module; 0 if not.
#
# NOTES
#   Only asmcmdcore_shell() calls this routine.
########
sub asmcmdtmpl_process_cmd 
{
  my ($dbh) = @_;
  my ($succ) = 0;

  # Get current command from global value, which is set by 
  # asmcmdtemplate_parse_asmcmd_args()and by asmcmdcore_shell().
  my ($cmd) = $asmcmdglobal_hash{'cmd'};

  # Declare and initialize hash of function pointers, each designating a 
  # routine that processes an ASMCMDTEMPLATE command.
  my (%cmdhash) = ( lstmpl      => \&asmcmdtmpl_process_lstmpl,
                    mktmpl      => \&asmcmdtmpl_process_mktmpl,
                    chtmpl      => \&asmcmdtmpl_process_chtmpl,
                    rmtmpl      => \&asmcmdtmpl_process_rmtmpl );

  if (defined ( $cmdhash{ $cmd } ))
  {    # If user specifies a known command, then call routine to process it. #
    $cmdhash{ $cmd }->($dbh);
    $succ = 1;
  }

  return $succ;
}


########
# NAME
#   asmcmdtmpl_process_lstmpl
#
# DESCRIPTION
#   This function processes the asmcmd command lstmpl.
#
# PARAMETERS
#   dbh   (IN) - initialized database handle, must be non-null.
#
# RETURNS
#   Null.
#
# NOTES
#   Only asmcmdtmpl_process_cmd() calls this function.
########
sub asmcmdtmpl_process_lstmpl
{
  my ($dbh) = shift;

  my (%args);
  my ($qry, $ret);
  my (@what , @from, $sth, @where, @order);
  my (@cols, @dgroups, %dgnmap);
  my ($dgname, $dgnum, $meta, $vals);
  my ($header, $pattern);
  my (%as);
  my (@tmpl_list);
  my ($row, $k, $v, $h);

  my (%min_col_wid, $print_format, $printf_code, @what_print);

  # Get option parameters, if any.
  $ret = asmcmdtmpl_parse_int_args($asmcmdglobal_hash{'cmd'}, \%args); 
  return unless defined ($ret);

  #Set the correct options if deprecated options were used and print WARNING.
  asmcmdshare_handle_deprecation($asmcmdglobal_hash{'cmd'},\%args);

  # get disk group names
  @dgroups = asmcmdshare_get_dg($dbh);

  foreach (@dgroups)
  {
    $dgnmap{$_->{'group_number'}} = $_->{'name'};
  }

  # if disk group is specified, filter out
  if (defined($args{'G'}))
  {
    $dgname = $args{'G'};
    $dgname =~ tr/[a-z]/[A-Z]/;
    $dgnum = asmcmdshare_get_gnum_from_gname($dbh, $dgname);
  }

  # check if -l is specified
  $vals   = defined($args{'l'});

  # check if pattern is specified
  if (defined($ARGV[0]))
  {
    $pattern= $ARGV[0];
    $pattern =~ s,$ASMCMDGLOBAL_WCARD_CHARS,\%,g;
  }

  push (@what, 'group_number');
  push (@what, 'name');

  push (@order, 'group_number');
  push (@order, 'name');

  # add extra columns if specified
  if ($vals)
  {
    push (@what, 'stripe');
    push (@what, 'system');
    push (@what, 'redundancy');
    push (@what, 'primary_region');
    push (@what, 'mirror_region');
  }

  # filter out template name
  if ($pattern)
  {
    $pattern =~ tr/[a-z]/[A-Z]/;
    push (@where, 'name LIKE \'%' . $pattern . '%\' ');
  }

  # filter out diskgroup
  if (defined($dgnum))
  {
    push (@where, 'group_number = \'' . $dgnum . '\' ');
  }

  push (@from, 'v$asm_template');

  $sth = asmcmdshare_do_construct_select($dbh, \@what, \@from, \@where,
                                         \@order);

  asmcmdshare_trace(1, $DBI::errstr, 'y', 'y') unless defined ($sth);

  #initialize the min_col_wid array
  foreach(@what)
  {
    $min_col_wid{$_} = 0;
  }
  $min_col_wid{'group_name'} = 0;

  #get the rows
  while (defined($row = asmcmdshare_fetch($sth)))
  {
    my(%tmpl_info) = ();

    while(($k, $v) = each(%{$row}))
    {
      $k =~ tr/[A-Z]/[a-z]/;
      $tmpl_info{$k} = $v;

      $min_col_wid{$k} = max($min_col_wid{$k}, length($v));
    }

    if (defined($tmpl_info{'group_number'}))
    {
      $tmpl_info{'group_name'} = $dgnmap{$tmpl_info{'group_number'}};

      $min_col_wid{'group_name'} = max( $min_col_wid{'group_name'},
                                        length($tmpl_info{'group_name'}));
    }

    push (@tmpl_list, \%tmpl_info);
  }
  asmcmdshare_finish($sth);

  # add the group_name column at the beginning, we do this because it was not
  # part of the query
  unshift @what, "group_name";

  #get the header length
  foreach (@what)
  {
    $min_col_wid{$_} = max($min_col_wid{$_}, 
                           length($asmcmdtmpl_lstmpl_header{$_}));
  }

  #create print format
  $print_format = '';

  foreach (@what)
  {
    $print_format .= "%-$min_col_wid{$_}s  ";
  }
  $print_format .= "\\n";

  #print header
  if (!defined ($args{'suppressheader'}) )
  {
    $printf_code = "printf \"$print_format\", ";
    @what_print = ();
    foreach (@what)
    {
      push (@what_print, "\'" . $asmcmdtmpl_lstmpl_header{$_} . "\'");
    }
    $printf_code .= "(" . join (", ", @what_print) . ")";

    eval $printf_code;
  }

  #print rows
  foreach $h (@tmpl_list)
  {
    $printf_code = "printf \"$print_format\", ";
    @what_print = ();
    foreach (@what)
    {
      push (@what_print, "\'" . $h->{$_} . "\'");
    }
    $printf_code .= "(" . join (", ", @what_print) . ")";
    eval $printf_code;
  }
}

########
# NAME
#   asmcmdtmpl_process_mktmpl
#
# DESCRIPTION
#   This function processes the asmcmd command mktmpl.
#
# PARAMETERS
#   dbh   (IN) - initialized database handle, must be non-null.
#
# RETURNS
#   Null.
#
# NOTES
#   Only asmcmdtmpl_process_cmd() calls this function.
########
sub asmcmdtmpl_process_mktmpl
{
  my ($dbh) = shift;

  my (%args);
  my ($qry, $ret);
  my ($redun, $pri_zn, $sec_zn, $dgname);
  my ($name);
  my (@attrs);

  # Get option parameters, if any.
  $ret = asmcmdtmpl_parse_int_args($asmcmdglobal_hash{'cmd'}, \%args); 
  return unless defined ($ret);

  if (!defined($args{'G'}))
  {
    asmcmdtmpl_syntax_error($asmcmdglobal_hash{'cmd'});
    return;
  }
  $dgname = $args{'G'};

  if (!defined($ARGV[0]))
  {
    asmcmdtmpl_syntax_error($asmcmdglobal_hash{'cmd'});
    return;
  }
  $name = $ARGV[0];

  #striping
  if (defined($args{'striping'}))
  {
    push(@ARGV,"--".$args{'striping'});
    GetOptions (\%args, 'coarse','fine');
    pop(@ARGV);
    
    if(defined($args{'coarse'}) ^ defined($args{'fine'}))
    {  
      push (@attrs, 'COARSE') if (defined($args{'coarse'}));
      push (@attrs, 'FINE')   if (defined($args{'fine'}));
    }
    else
    {
      asmcmdtmpl_syntax_error($asmcmdglobal_hash{'cmd'});
      return; 
    }
  }

  #redundancy
  if (defined($args{'redundancy'}))
  {
    $redun = $args{'redundancy'};
    push(@ARGV,"--".$args{'redundancy'});
    GetOptions (\%args, 'unprotected','mirror','high');
    pop(@ARGV);

    # (A XOR B XOR C) && !(A AND B AND C)
    if((defined($args{'unprotected'}) ^ defined($args{'mirror'}) ^ 
       defined($args{'high'})) && 
       !(defined($args{'unprotected'}) && defined($args{'mirror'}) &&
       defined($args{'high'})))
    {
      push (@attrs, 'UNPROTECTED') if (defined($args{'unprotected'}));
      push (@attrs, 'MIRROR')   if (defined($args{'mirror'}));
      push (@attrs, 'HIGH')     if (defined($args{'high'}));
    }
    else
    {
      asmcmdtmpl_syntax_error($asmcmdglobal_hash{'cmd'});
      return;      
    }
  }

  #pri-zone
  if (defined($args{'primary'}))
  {
    $pri_zn = $args{'primary'};
    push(@ARGV,"--".$args{'primary'});
    GetOptions (\%args, 'hot','cold');
    pop(@ARGV);

    if(defined($args{'hot'}) ^ defined($args{'cold'}))
    {
      if(defined($args{'hot'}))
      {
        push (@attrs, 'HOT');
        delete($args{'hot'});
      }
      elsif(defined($args{'cold'}))
      {
        push (@attrs, 'COLD');
        delete($args{'cold'}); 
      }
    }
    else
    {
      asmcmdtmpl_syntax_error($asmcmdglobal_hash{'cmd'});
      return;
    }
  }

  #sec zone
  if (defined($args{'secondary'}))
  {
    $sec_zn = $args{'secondary'};
    push(@ARGV,"--".$args{'secondary'});
    GetOptions (\%args, 'hot','cold');
    
    if(defined($args{'hot'}) ^ defined($args{'cold'}))
    {
      if(defined($args{'hot'}))
      {
        push (@attrs, 'MIRRORHOT');
        delete($args{'hot'});
      }
      elsif(defined($args{'cold'}))
      {
        push (@attrs, 'MIRRORCOLD');
        delete($args{'cold'});
      }
    }
    else
    {
      asmcmdtmpl_syntax_error($asmcmdglobal_hash{'cmd'});
      return;
    }
  }

  $qry = "ALTER DISKGROUP " . $dgname . " ADD TEMPLATE " . $name;

  if (@attrs)
  {
    $qry .= ' ATTRIBUTES(' .join(' ', @attrs) . ')';
  }

  $ret= asmcmdshare_do_stmt($dbh, $qry);
  asmcmdshare_trace(1, $DBI::errstr, 'y', 'y') unless defined ($ret);
}


########
# NAME
#   asmcmdtmpl_process_chtmpl
#
# DESCRIPTION
#   This function processes the asmcmd command chtmpl.
#
# PARAMETERS
#   dbh   (IN) - initialized database handle, must be non-null.
#
# RETURNS
#   Null.
#
# NOTES
#   Only asmcmdtmpl_process_cmd() calls this function.
########
sub asmcmdtmpl_process_chtmpl
{
  my ($dbh) = @_;
  my (%args);
  my ($qry, $ret);
  my ($redun, $pri_zn, $sec_zn, $dgname);
  my ($name);
  my (@attrs);

  # Get option parameters, if any.
  $ret = asmcmdtmpl_parse_int_args($asmcmdglobal_hash{'cmd'}, \%args); 
  return unless defined ($ret);

  # get the diskgroup name
  if (!defined($args{'G'}))
  {
    asmcmdtmpl_syntax_error($asmcmdglobal_hash{'cmd'});
    return;
  }
  $dgname = $args{'G'};

  # get the template name
  if (!defined($ARGV[0]))
  {
    asmcmdtmpl_syntax_error($asmcmdglobal_hash{'cmd'});
    return;
  }
  $name = $ARGV[0];

  $qry = "ALTER DISKGROUP " . $dgname . " MODIFY TEMPLATE " . $name;

  #striping
  if (defined($args{'striping'}))
  {
    push(@ARGV,"--".$args{'striping'});
    GetOptions (\%args, 'coarse','fine');
    pop(@ARGV);
    
    if(defined($args{'coarse'}) ^ defined($args{'fine'}))
    {
      push (@attrs, 'COARSE') if (defined($args{'coarse'}));
      push (@attrs, 'FINE')   if (defined($args{'fine'}));
    }
    else
    {
      asmcmdtmpl_syntax_error($asmcmdglobal_hash{'cmd'});
      return;
    }
  }

  #redundancy
  if (defined($args{'redundancy'}))
  {
    $redun = $args{'redundancy'};
    push(@ARGV,"--".$args{'redundancy'});
    GetOptions (\%args, 'unprotected','mirror','high');
    pop(@ARGV);

   # (A XOR B XOR C) && !(A AND B AND C) 
   if((defined($args{'unprotected'}) ^ defined($args{'mirror'}) ^
       defined($args{'high'})) &&
      !(defined($args{'unprotected'}) && defined($args{'mirror'}) &&
       defined($args{'high'})))
    {
      push (@attrs, 'UNPROTECTED') if (defined($args{'unprotected'}));
      push (@attrs, 'MIRROR')   if (defined($args{'mirror'}));
      push (@attrs, 'HIGH')     if (defined($args{'high'}));
    }
    else
    {
      asmcmdtmpl_syntax_error($asmcmdglobal_hash{'cmd'});
      return;
    }
  }

  #pri-zone
  if (defined($args{'primary'}))
  {
    $pri_zn = $args{'primary'};
    push(@ARGV,"--".$args{'primary'});
    GetOptions (\%args, 'hot','cold');
 
    if(defined($args{'hot'}) ^ defined($args{'cold'}))
    {
      if(defined($args{'hot'}))
      {
        push (@attrs, 'HOT');
        delete($args{'hot'});
      }
      elsif(defined($args{'cold'}))
      {
        push (@attrs, 'COLD');
        delete($args{'cold'});
      }
    }
    else
    {
      asmcmdtmpl_syntax_error($asmcmdglobal_hash{'cmd'});
      return;
    }
 }

  #sec zone
  if (defined($args{'secondary'}))
  {
    $sec_zn = $args{'secondary'};
    push(@ARGV,"--".$args{'secondary'});
    GetOptions (\%args, 'hot','cold');

    if(defined($args{'hot'}) ^ defined($args{'cold'}))
    {
      if(defined($args{'hot'}))
      {
        push (@attrs, 'MIRRORHOT');
        delete($args{'hot'});
      }
      elsif(defined($args{'cold'}))
      {
        push (@attrs, 'MIRRORCOLD');
        delete($args{'cold'});
      }
    }
    else
    {
      asmcmdtmpl_syntax_error($asmcmdglobal_hash{'cmd'});
      return;
    }
  }

  if (@attrs)
  {
    $qry .= ' ATTRIBUTES(' .join(' ', @attrs) . ')';
  }

  $ret= asmcmdshare_do_stmt($dbh, $qry);
  asmcmdshare_trace(1, $DBI::errstr, 'y', 'y') unless defined ($ret);
}


########
# NAME
#   asmcmdtmpl_process_rmtmpl
#
# DESCRIPTION
#   This function processes the asmcmd command rmtmpl.
#
# PARAMETERS
#   dbh   (IN) - initialized database handle, must be non-null.
#
# RETURNS
#   Null.
#
# NOTES
#   Only asmcmdtmpl_process_cmd() calls this function.
########
sub asmcmdtmpl_process_rmtmpl
{
  my ($dbh) = shift;

  my (%args);
  my ($qry, $ret);
  my ($dgname, $name);

  # Get option parameters, if any.
  $ret = asmcmdtmpl_parse_int_args($asmcmdglobal_hash{'cmd'}, \%args); 
  return unless defined ($ret);

  # get the diskgroup name
  if (!defined($args{'G'}))
  {
    asmcmdtmpl_syntax_error($asmcmdglobal_hash{'cmd'});
    return;
  }
  $dgname = $args{'G'};

  # get the template name
  if (!defined($ARGV[0]))
  {
    asmcmdtmpl_syntax_error($asmcmdglobal_hash{'cmd'});
    return;
  }
  $name = $ARGV[0];

  $qry = "ALTER DISKGROUP " . $dgname . " DROP TEMPLATE " . $name;

  $ret= asmcmdshare_do_stmt($dbh, $qry);
  asmcmdshare_trace(1, $DBI::errstr, 'y', 'y') unless defined ($ret);
}


########
# NAME
#   asmcmdtmpl_is_cmd
#
# DESCRIPTION
#   This routine checks if a user-entered command is one of the known
#   ASMCMD internal commands that belong to the ASMCMDTMPL module.
#
# PARAMETERS
#   arg   (IN) - user-entered command name string.
#
# RETURNS
#   True if $arg is one of the known commands, false otherwise.
########
sub asmcmdtmpl_is_cmd 
{
  my ($arg) = shift;

  return defined ( $asmcmdtmpl_cmds{ $arg } );
}


########
# NAME
#   asmcmdtmpl_is_wildcard_cmd
#
# DESCRIPTION
#   This routine determines if an ASMCMDTMPL command allows the use 
#   of wild cards.
#
# PARAMETERS
#   arg   (IN) - user-entered command name string.
#
# RETURNS
#   True if $arg is a command that can take wildcards as part of its argument, 
#   false otherwise.
########
sub asmcmdtmpl_is_wildcard_cmd 
{
  my ($arg) = shift;

  return defined ($asmcmdtmpl_cmds{ $arg }) &&
         defined ($asmcmdtmpl_cmds{ $arg }{ wildcard });
}


########
# NAME
#   asmcmdtmpl_is_no_instance_cmd
#
# DESCRIPTION
#   This routine determines if a command can run without an ASM instance.
#
# PARAMETERS
#   arg   (IN) - user-entered command name string.
#
# RETURNS
#   True if $arg is a command that can run without an ASM instance 
#   or does not exist, false otherwise.
#
# NOTES
#   The asmcmdtmpl module currently supports only the help as a command
#   that does not require an ASM instance.
########
sub asmcmdtmpl_is_no_instance_cmd 
{
  my ($arg) = shift;

  return !defined ($asmcmdtmpl_cmds{ $arg }) ||
         !defined ($asmcmdtmpl_cmds{ $arg }{ no_instance });
}


########
# NAME
#   asmcmdtmpl_parse_int_args
#
# DESCRIPTION
#   This routine parses the arguments for flag options for ASMCMD internal
#   commands.
#
# PARAMETERS
#   cmd      (IN)  - user-entered command name string.
#   args_ref (OUT) - hash of user-specified flag options for a command, 
#                    populated by getopts().
#
# RETURNS
#   Zero on success; undefined on error.
#
# NOTES
#   $cmd must already be verified as a valid ASMCMD internal command.
########
sub asmcmdtmpl_parse_int_args
{
  my ($cmd, $args_ref) = @_;
  my @string;
  my $key;

  #build the list of options to parse using GetOptions
  if($asmcmdtmpl_cmds{ $cmd }{ flags })
  {
    foreach $key(keys %{$asmcmdtmpl_cmds{ $cmd }{ flags }})
    {
      push(@string, $key);
    }
  }

  #include deprecated options if any
  if($asmcmdglobal_deprecated_options{ $cmd })
  {
    foreach $key(keys %{$asmcmdglobal_deprecated_options{ $cmd }})
    {
      push(@string, $asmcmdglobal_deprecated_options{$cmd}{$key}[0]);
    }
  }

  # Use GetOptions() from the Getopt::Long package to parse arguments for
  # internal commands.  These arguments are stored in @ARGV.
  if (!GetOptions($args_ref,@string))
  {
    # Print correct command format if syntax error. #
    asmcmdtmpl_syntax_error($cmd);
    return undef;
  }

  return 0;
}


########
# NAME
#   asmcmdtmpl_syntax_error
#
# DESCRIPTION
#   This routine prints the correct syntax for a command to STDERR, used 
#   when there is a syntax error.  If the command with bad syntax is asmcmd 
#   itself, then asmcmdbase_syntax_error also calls exit() to quit out.
#
# PARAMETERS
#   cmd   (IN) - user-entered command name string.
#
# RETURNS
#   1 if another command that belongs to this module; 0 if command not found.
#
# NOTES
#   These errors are user-errors and not internal errors.  They are of type
#   record, not signal.  Thus, even if exit() is called, the exit value is
#   zero.
########
sub asmcmdtmpl_syntax_error 
{
  my ($cmd) = shift;
  my ($cmd_syntax);                               # Correct syntax for $cmd. #
  my ($succ) = 0;

  if (asmcmdtmpl_is_cmd($cmd))
  {
    $cmd_syntax = asmcmdshare_get_help_syntax($cmd);  # Get syntax for $cmd. #
    $cmd_syntax = asmcmdshare_trim_str ($cmd_syntax);

    if (defined ($cmd_syntax))
    {
      print STDERR 'usage: ' . $cmd_syntax . "\n";
      print STDERR 'help:  help ' . $cmd . "\n";
      $succ = 1;
    }
  }

  return $succ;
}


########
# NAME
#   asmcmdtmpl_get_cmd_syntax
#
# DESCRIPTION
#   This routine returns the help syntax of the command specified by $cmd.
#
# PARAMETERS
#   cmd   (IN) - the name of the command of which we're looking up the 
#                syntax.
#
# RETURNS
#   The syntax for command $cmd; undefined if $cmd does not exist.
########
sub asmcmdtmpl_get_cmd_syntax 
{
  my ($cmd) = shift;
  my (%cmd_syntax);     # Hash storing the syntax for each internal command. #

  $cmd_syntax{'lstmpl'}  = 'lstmpl [-l] [--suppressheader] [-G dgname]
                            [pattern]';
  $cmd_syntax{'mktmpl'}  = 'mktmpl <-G dgname>  [--striping <coarse|fine>] '.
                           '[--redundancy <unprotected|mirror|high>] '.
                           '[--primary <hot|cold>] [--secondary <hot|cold>]'.
                           ' name';
  $cmd_syntax{'chtmpl'}  = 'chtmpl <-G dgname> [--striping <coarse|fine>] ' .
                           '[--redundancy <unprotected|mirror|high>] '.
                           '[--primary <hot|cold>] [--secondary <hot|cold>]'.
                           ' name';
  $cmd_syntax{'rmtmpl'}  = 'rmtmpl <-G dgname> name';

  return $cmd_syntax{$cmd};
}


########
# NAME
#   asmcmdtmpl_process_help
#
# DESCRIPTION
#   This function is the help function for the asmcmdtmpl module.
#
# PARAMETERS
#   command     (IN) - display the help message for this command.
#
# RETURNS
#   1 if command found; 0 otherwise.
########
sub asmcmdtmpl_process_help 
{
  my ($command) = shift;       # User-specified argument; show help on $cmd. #
  my ($desc);                                # Command description for $cmd. #
  my ($succ) = 0;                         # 1 if command found, 0 otherwise. #

  if (asmcmdtmpl_is_cmd ($command)) 
  {                              # User specified a command name to look up. #
    $desc = asmcmdshare_get_help_desc($command);
    print "$desc\n";
    $succ = 1;
  }

  return $succ;
}


########
# NAME
#   asmcmdtmpl_get_asmcmd_cmds
#
# DESCRIPTION
#   This routine constructs a string that contains a list of the names of all 
#   ASMCMD internal commands and returns this string.
#
# PARAMETERS
#   None.
#
# RETURNS
#   A string contain a list of the names of all ASMCMD internal commands.
#
# NOTES
#   Used by the help command and by the error command when the user enters
#   an invalid internal command.
########
sub asmcmdtmpl_get_asmcmd_cmds 
{
  my ($asmcmd_cmds) = "        chtmpl, lstmpl, mktmpl, rmtmpl\n" ;

  return ($asmcmd_cmds);
}
1;
