#!/usr/bin/perl
# IBM_PROLOG_BEGIN_TAG 
# This is an automatically generated prolog. 
#  
#  
#  
# Licensed Materials - Property of IBM 
#  
# (C) COPYRIGHT International Business Machines Corp. 2000,2019 
# All Rights Reserved 
#  
# US Government Users Restricted Rights - Use, duplication or 
# disclosure restricted by GSA ADP Schedule Contract with IBM Corp. 
#  
# IBM_PROLOG_END_TAG 
# sccsid = "@(#)09   1.58   src/rsct/rmc/cli/bin/mkrsrc.perl, rmccli, rsct_rady, rady2035a 11/12/15 16:30:06"
######################################################################
#                                                                    #
# Module: mkrsrc                                                     #
#                                                                    #
# Purpose:                                                           #
#   mkrsrc - Makes (defines) a new resource.                         #
#                                                                    #
# Syntax:                                                            #
#   To define a new resource using data entered on the command line: #
#   mkrsrc [-h] [-v] [ -N { node_file | "-" } ] [-T] [-V]            #
#          Resource_class  Attr=value... [Arg=value...]              #
#                                                                    #
#   To define a new resource using data predefined in an input file: #
#   mkrsrc [-h] -f Resource_data_input_file [-v]                     #
#          [ -N { node_file | "-" } ][-T] [-V] Resource_class        #
#                                                                    #
#   To see examples of the mkrsrc command for a resource class:      #
#   mkrsrc [-h] -e [-T] [-V] Resource_class                          #
#                                                                    #
# Flags:                                                             #
#   -h      Help. Writes this command's usage statement to stdout.   #
#   -f Resource_data_input_file File input. Specifies the name of    #
#           the file which contains resource attribute information.  #
#           PersistentResourceAttributes::                           #
#           Resource 1:                                              #
#               attr1 = value                                        #
#               attr2 = value                                        #
#           Resource 2:                                              #
#               attr1 = value                                        #
#               attr2 = value                                        #
#           PersistentResourceArguments::                            #
#           Resource 1:                                              #
#               arg1 = value                                         #
#               arg2 = value                                         #
#           Resource 2:                                              #
#               arg1 = value                                         #
#               arg2 = value                                         #
#           If arguments are specified there must be one set of      #
#           resource arguments for each set of resource attributes.  #
#           Multiple resource instances can be defined in this file. #
#   -e      Example. Displays two examples of suitable command line  #
#           input for this command.                                  #
#           * Example of mkrsrc command line input for required      #
#             attributes only.                                       #
#           * Example of mkrsrc command line input for both required #
#             and optional attributes.                               #
#             In addition if any arguments are defined they are      #
#             displayed right after the optional attributes.         #
#   -v      Verify. Verifies that all of the specified attributes    #
#           are valid persistent attribute names that have either    #
#           a "reqd_for_define" or "option_for_define" property.     #
#           If any command argument is specified it verifies that    #
#           it is a valid command argument name and that all command #
#           arguments have been entered. Does not actually define    #
#           the resources.                                           #
#   -N { node_file | "-" }  Specifies that node names are read from  #
#           a file or from standard input. Use -N node_file to       #
#           indicate that the node names are in a file.              #
#           o There is one node name per line in node_file           #
#           o A number sign (#) in column 1 indicates that the line  #
#             is a comment                                           #
#           o Any blank characters to the left of a node name are    #
#             ignored                                                #
#           o Any characters to the right of a node name are ignored #
#           Use -N "-" to read the node names from standard input.   #
#   -T      Trace. Writes the command's trace messages to standard   #
#           error. For your software-service organization use only.  #
#   -V      Verbose. Writes this command's verbose messages to       #
#           standard output.                                         #
#                                                                    #
# Operands:                                                          #
#   Resource_class  The resource class name of the resource to be    #
#                   defined.                                         #
#                                                                    #
#   Attr=value      Attributes of the resource being defined. When   #
#                   defining a new resource instance, there are      #
#                   specific required attributes for each resource   #
#                   that must be defined. These attributes can be    #
#                   specified on the command line or defined in an   #
#                   input file and specifying the -f flag.           #
#                                                                    #
#   Attr            The name of a persistent attribute for this      #
#                   resource. The attribute must have a property of  #
#                   "reqd_for_define" or "option_for_define". Use    #
#                   the lsrsrcdef command to check the property.     #
#                                                                    #
#   value           The value for this persistent attribute. The     #
#                   data type for this value must match the defined  #
#                   for the value of this attribute. Use the         #
#                   lsrsrcdef command to verify the data type for    #
#                   each attribute.                                  #
#                                                                    #
#   Arg=value       Enter the command arguments names and values.    #
#                   Command arguments are optional.                  #
#                   If any Arg=value pairs are entered then there    #
#                   should be one Arg=value pair for each of the     #
#                   the command arguments defined for the define     #
#                   function for the specified resource class.       #
#                   Use mkrsrc -e to get the list of command         #
#                   arguments names and data types for the specific  #
#                   resource class.                                  #
#                   Use the lscmdargdef command to view the command  #
#                   arguments definition.                            #
#   Arg             The argument name.                               #
#   value           The value for this argument, the value data type #
#                   must match the definition of arguments data type.#
#                   Use the lscmdargdef command to verify the data   #
#                   type for each argument.                          #
#                                                                    #
# Description:                                                       #
#   The mkrsrc command requests the RMC subsystem to define a new    #
#   resource instance for the class specified by the Resource_class  #
#   operand. At least one persistent attribute name and its value    #
#   must be specified either as an operand or by a resource          #
#   definition file using the -f flag.                               #
#                                                                    #
#   Prior to running mkrsrc, you should run the lsrsrcdef command    #
#   to determine which attributes must be specified when defining    #
#   the resource. Attributes that have a "reqd_for_define" property  #
#   must be specified on the command line or in the input file.      #
#   Attributes that have a "option_for_define" property are optional.#
#   The lsrsrcdef command also identifies the data type for each     #
#   attribute. The value specified for each attribute must match     #
#   this data type.                                                  #
#                                                                    #
#   Example of Resource Data Input File which can be used as input   #
#   to mkrsrc when -f flag is specified.                             #
#   vi /tmp/IBM.Foo.rdef                                             #
#   # Comment character is #                                         #
#   # AttributeName = Value pairs, spaces or tabs are allowed before #
#   #   or after the AttributeName, =, or Value.                     #
#   # All resources between PersistentResourceAttributes and the eof #
#   # or a :: will be processed by mkrsrc.                           #
#   # Next line is required exactly as written below.                #
#   PersistentResourceAttributes::                                   #
#   resource 1:                                                      #
#       Name=c175n04                                                 #
#       NodeList = {1}                                               #
#       BinaryArray= {"0x01", "0x02", "0x0304"}                      #
#       SDArray = {[hello,1,{0,1,2,3}],[hello2,2,{2,4,6,8}]}         #
#       String="hello"                                               #
#                                                                    #
#   resource 2:                                                      #
#       Name = "c175n05"                                             #
#       NodeList = {1}                                               #
#       SDArray = {["hel  lo1",1,{0,1,2}],[hello2,2,{3,4,5}]}        #
#                                                                    #
# Exit Values:                                                       #
#   0  MC_CLI_SUCCESS        Command completed successfully.         #
#   1  MC_CLI_RMC_ERROR      Command terminated due to an underlying #
#                            RMC error.                              #
#   2  MC_CLI_ERROR          Command terminated due to an underlying #
#                            error in the command script.            #
#   3  MC_CLI_BAD_FLAG       Command terminated due to user          #
#                            specifying an invalid flag.             #
#   4  MC_CLI_BAD_OPERAND    Command terminated due to user          #
#                            specifying a bad operand.               #
#   5  MC_CLI_USER_ERROR     Command terminated due to a user error. #
#                            For example specifying an undefined     #
#                            Resource name as the Resource operand.  #
#                                                                    #
# Examples:                                                          #
#   mkrsrc IBM.Foo Name=c175n05 NodeNumber=1                         #
#   mkrsrc -f /tmp/IBM.Foo.rdef IBM.Foo                              #
#                                                                    #
# Man Page:                                                          #
#   For the most current detailed description of this command see    #
#   the mkrsrc man page in /opt/rsct/man.                       #
#                                                                    #
#--------------------------------------------------------------------#
# Inputs:                                                            #
#   /opt/rsct/msgmaps/mccli.mkrsrc.map - message mapping        #
#   /opt/rsct/msgmaps/mccli.mccli.map - message mapping         #
#                                                                    #
# Outputs:                                                           #
#   stdout - any verbose messages.                                   #
#   stderr - any error message.                                      #
#                                                                    #
# External Ref:                                                      #
#   Commands: ctdspmsg                                               #
#   Modules:  MC_cli_utils.pm, MC_cli_rc.pm                          #
#             CT_cli_utils.pm, CT_cli_data_type_utils,               #
#             CT_cli_input_utils, CT_cli_display_utils.              #
#   Extensions:  CT::MC, CT::MCerr, CT::CT                           #
#   Perl library routines: Getopt::Std                               #
#                                                                    #
# Tab Settings:                                                      #
#   4 and tabs should be expanded to spaces before saving this file. #
#   in vi:  (:set ts=4  and   :%!expand -4)                          #
#                                                                    #
# Change Activity:                                                   #
#   000315 SAB 60909: Initial design & write.                        #
#   001106 GTM 67900: Change -e per review comments                  #
#   010311 SAB 63852: Prepared for GA.                               #
#   010813 SAB 75111: Added support for command arguments.           #
#   020114 JAC 78199: Add optional parm for cmd args call to process #
#                     input and fix error message.                   #
#   020925 JAC 87393: Change CT_cli_display_utils to .._displayext.. #
#   021203 JAC 88085: Modify call to get_sd_defs_api.                #
#   030212 JAC 89941: Process SD differently for binaries and RHs.   #
#   030220 JAC 92003: Some commas incorrect in setup_mkrsrcapi.      #
#   040406 JAC 105863: Use new escape_chars function for escaping    #
#   040426 JAC 108105: Fix a typo.                                   #
#   050707 JAC 116172: Calculate CMD_LIMIT instead of using const.   #
#   051020 JAC 125712: Use mkrsrc-api -f option when cmd too long.   #
#   051116 JAC 131200: Check for multiple non-array attributes.      #
#   051213 JAC 131854: Bad 131200 change. Don't check SDs.           #
#   060614 JAC 135966: Fix quotes for file input strings.            #
#   070516 JAC 132926: Add -N and allow for >1 node in NodeNameList. #
#   070607 JAC 144354: Only handle >1 node for subdivided classes.   #
#   070803 JAC 145853: check for -N used with NodeNameList.          #
#   080718 JAC 152239: -e not valid if class cannot define resources.#
######################################################################

#--------------------------------------------------------------------#
# General Program Flow/Logic:                                        #
#                                                                    #
# A. Parse command line flags and operands, determine which flavor   #
#    of this command we are actually invoking.                       #
#    This command allows a user to:                                  #
#       * Define a resource using Attr=value pairs specified on the  #
#         command line.                                              #
#       * Define one or more resources using Attr=value pairs        #
#         that were predefined in a resource data input file in      #
#         stanza format with the PersistentResourceAttributes::      #
#         keyword to indicate start of the stanzas and Resource 1:   #
#         keyword to separate each resource.                         #
#       * Request an example of suitable input for the specified     #
#         Resource_class to the mkrsrc command.                      #
#       * Verify that the attributes they are specifying are valid   #
#         persistent attributes for the specified resource class and #
#         have "reqd_for_define" or "option_for_define" property.    #
# B. Initialize a session with RMC.                                  #
# C. Query the definition of the specified resource class using RMC. #
#    Need to get the required and optional attribute data types.     #
#    And the data types for any required SD elements.                #
# D. If requested, print out the example of input to mkrsrc.         #
# E. Parse the Attr=value pairs from either the command line or      #
#    input file.                                                     #
# F. If requested, verify that the attributes specified are valid    #
#    and have the appropriate properties.                            #
# G. Define the resource or resources.                               #
# H. Cleanup.                                                        #
#--------------------------------------------------------------------#

#--------------------------------------------------------------------#
# Included Libraries and Extensions                                  #
#--------------------------------------------------------------------#
use lib "/opt/rsct/pm";
use locale;
use Getopt::Std; 


use autouse CT_cli_utils => qw(
    printIMsg
    printEMsg
    calc_cmdarg_length
);
use autouse CT_cli_input_utils => qw(
    process_input_file
    process_cmdline_input
    escape_chars
    check_input_file
);
use autouse CT_cli_displayext_utils => qw(
    rsrc_handle_to_string
);

use MC_cli_rc qw(:return_codes);
use MC_cli_utils qw(
    get_p_attr_defs_api
    get_arg_defs_api
    get_sd_defs_api
    qdef_resource_class_api
    build_cmd_arg_sd_api
    error_exit
    printCEMsg
    convert_input_value_api
    process_exit_code
    process_api_error
    remove_api_error
    read_from_Stdin
    $RMC_RSRC_PATTR_REQD_FOR_DEFINE
    $RMC_RSRC_PATTR_OPTION_FOR_DEFINE
    $RMC_CLASS_MTYPE_SUBD
    $RMC_CLASS_CAN_DEF_UNDEF
);


#--------------------------------------------------------------------#
# Global Variables                                                   #
#--------------------------------------------------------------------#
$TRUE = 1;
$FALSE = 0;

$Verbose = $FALSE;                      # default - verbose turned off

# By default output, attribute name value pairs should be entered
# via the command line.  Attr=value   e.g. Name=c175n06 NodeNumber=1
$Opt_File_Input = $FALSE;               # default - see -f (file form)
$Opt_Example = $FALSE;                  # default - see -e (example)
$Opt_Verify = $FALSE;                   # default - see -v (verify)
$Opt_Node_File = $FALSE;                # default - see -N (node file)
$Opt_Stdin = $FALSE;                    # default - see -N (node file)

$PROGNAME = "mkrsrc";                   # Program Name for messages
$MSGCAT = "mccli.cat";                  # msg catalogue for this cmd

$CTDIR = "/opt/rsct";              # RSCT root directory 
$CTBINDIR = "$CTDIR/bin";               # Cluster Bin directory path
$LSMSG = "$CTBINDIR/ctdspmsg";          # list / display message rtn.
$ENV{'MSGMAPPATH'} = "$CTDIR/msgmaps";  # msg maps used by $LSMSG 

#--------------------------------------------------------------------#
# Variables                                                          #
#--------------------------------------------------------------------#
%HoPAttrDefs = ();                      # Hash of Persistent Attribute
                                        # definitions
@LoPAttr = ();                          # Ordered list of Pers Attr
%HoSDAttrDefs = ();
my %HoSDArgDefs = ();                   # Hash of Command SD Arguments
                                        # element definitions
my @LoSDArgs = ();                      # Array of SD Cmd Arg Elements
                                        # (type, value) ordered by
                                        # element id.
my @LoSDArgNames = ();
my @mkrsrcapi_parms = ();               # parameters to send to mkrsrcapi
my $node_file_name = "";                # file name for -N
my $nodenamelist_found = $FALSE;        # NodeNameList attr present
my @attr_list = ();                     # list of attr names

%HoNLSData = ();
my $badrc = 0;
my $opt_info = 0;
my $rLoCInfo = "";

$DELIMITER = "tvrtvrtvr";               # delimiter for mkrsrc-api

#--------------------------------------------------------------------#
# Main Code                                                          #
#--------------------------------------------------------------------#

# parse the command line, exit if there are errors 
my ($rc, $resource, $filename, $node_file_name, $r_cmdline) = &parse_cmd_line;
($rc == 0) || error_exit($rc);

# get the command line buffer length
$CMD_LIMIT = calc_cmdarg_length;

# Get the persistent attribute definitions for this resource class 
# and build a hash indexed using the persistent attribute program name
# that will allow easy access to each attributes id, data type
# and property definitions. 
# The resource must already have been defined for an instance to 
# be defined/created.
my $req_properties = $RMC_RSRC_PATTR_REQD_FOR_DEFINE |
                     $RMC_RSRC_PATTR_OPTION_FOR_DEFINE;
my @req_attributes = ();
$rc = get_p_attr_defs_api($resource, 0, $req_properties, 
    \@req_attributes, \@LoPAttr, \%HoPAttrDefs); 
($rc == 0) || error_exit($rc);

# Check if any of the Attributes are SDs, if they are required or
# optional for define (properties) then build HoSDAttrDefs 
$rc = get_sd_defs($resource, \%HoPAttrDefs, \%HoSDAttrDefs);
($rc == 0) || error_exit($rc);

# Get the define command SD argument definitions for this resource
# class. The returned hash level 1 key will be the SD element name.
$rc = get_arg_defs_api($resource, "", "define", 1, \%HoSDArgDefs,
                       \@LoSDArgNames);
($rc == 0) || error_exit($rc);

if ($Opt_Ls_Cmd_Args) {
    ls_cmd_args($resource, \@LoSDArgNames, \%HoSDArgDefs);
}
elsif ($Opt_Example) {
    # Print out an example of how to run mkrsrc, required and optional
    # attributes and arguments, but don't actually define any resources

    # get the class information to see if this class supports define
    $opt_info = $FALSE;
    ($rc, $rLoCInfo) = qdef_resource_class_api($resource, $opt_info);
    ($rc == 0) || exit($rc);

    # look for can_define. If ok, then proceed to examples
    if ($$rLoCInfo[0] =~ /$RMC_CLASS_CAN_DEF_UNDEF/) {
        ls_mkrsrc_example($resource, \%HoPAttrDefs, \%HoSDArgDefs);
    }
    else {
        # return an error that mkrsrc can't be used for this class
        printEMsg("EMsgmkrsrcExamplesNotValid", $resource);
        exit(MC_CLI_USER_ERROR);
    }
}
else {
    # If reading resource data from an input file get the    
    # NLSTranslation stanza data if it exists in this file
    if ($Opt_File_Input) {
        $rc = process_nls_input($filename, \%HoPAttrDefs,
            \%HoSDAttrDefs, \%HoNLSData);
        ($rc == 0) || error_exit($rc);
    }

    # Get the attr=value pairs and any arg=value pairs from either the
    # command line or the input file.
    ($rc, $rLoRsrcAttrData, $rLoRsrcArgData) = process_input(
        $Opt_File_Input, $filename, \%HoPAttrDefs, \%HoSDArgDefs, 
        $r_cmdline);
    ($rc == 0) || error_exit($rc);  

    # Merge the attr=value pairs you got from the user with the 
    # resources actual attribute definitions to build a Hash of 
    # Persistent Attributes which contains the equivalent data as 
    # the mc_attribute_t structure ({at_name} {at_dtype} {at_value}) 
    # The data you need to actually define the resource - also 
    # check that the user supplied values for all the required 
    # attributes
    foreach $new_resource (@$rLoRsrcAttrData)
    {
        ($rc, $rHoPAttr) = build_resource($resource, $new_resource, 
            \%HoPAttrDefs, \%HoSDAttrDefs, \%HoNLSData);
        if ($rc != 0) {
            if (!$badrc) { $badrc = $rc; }
            next;
        }

        # Process the command arguments if any were specified.
        if (defined($rLoRsrcArgData) && scalar keys(%HoSDArgDefs) > 0) {
            $new_cmd_args = shift (@$rLoRsrcArgData);
            ($rc, @LoSDArgs) = build_cmd_arg_sd_api($resource, 
                $new_cmd_args, \%HoSDArgDefs);
            if ($rc != 0) {
                if (!$badrc) { $badrc = $rc; }
                next;
             }
        }

        # If running in Verify mode, skip to next resource
        $Opt_Verify && next;            
       
        # Build parameters for mkrsrc-api command 

        @mkrsrcapi_parms = setup_mkrsrcapi(\@mkrsrcapi_parms, $resource, 
                                       $rHoPAttr, \@LoSDArgs);

        # determine if NodeNameList specified (used for setting scope later)
        @attr_list = keys %$rHoPAttr;
        foreach $attr_spec (@attr_list) {
           if ( $attr_spec =~ /^NodeNameList/ ) { $nodenamelist_found = $TRUE; }
        }
    }   # end foreach $new_resource

    ($badrc == 0) || error_exit($badrc);

    # 145853. If -N and NodeNameList used together, display error.
    if ( $Opt_Node_File && $nodenamelist_found ) { 
       printCEMsg("EMsgMCcliImproperUsageCombination", "-N", "NodeNameList");
       exit MC_CLI_BAD_FLAG;
    }

    # if -N used or NodeNameList specified, and the scope environment variable
    # is not set, see if this is a subdivided or globalized managed class.
    # if it's subdivided, set the scope to DM_SR.
    if ( ($Opt_Node_File || $nodenamelist_found) && 
         (!defined $ENV{CT_MANAGEMENT_SCOPE}) ) {

       # get the class information
       $opt_info = $FALSE;
       ($rc, $rLoCInfo) = qdef_resource_class_api($resource, $opt_info);
       ($rc == 0) || exit($rc);
       
       # look for subdivided
       if ($$rLoCInfo[0] =~ /$RMC_CLASS_MTYPE_SUBD/) {
          $ENV{CT_MANAGEMENT_SCOPE} = 4;
       }
    }

    # Define the resource(s). 
    $rc = define_resource(\@mkrsrcapi_parms, $node_file_name);

    if ($rc != 0) {
       $badrc = $rc;            # more important rc
    }

}  # end if not example

($badrc == 0) || error_exit($badrc);

exit($rc);


#--------------------------------------------------------------------#
# End Main Code                                                      #
#--------------------------------------------------------------------#


#--------------------------------------------------------------------#
# parse_cmd_line - Parse the command line for options and operands.  #
#   Set appropriate global variables as outlined below, make sure we #
#   have a valid combination of arguments / options.                 #
#                                                                    #
# Return:                                                            #
#   $rc   0                  Command line parsed fine, no problem.   #
#         SR_CLI_BAD_FLAG    Command line contained a bad flag.      #
#   $resource                Resource Class Name.                    #
#   $rsrc_file               Name of file that contains rsrc data    #
#   @cmdline_args            Reference to an array of                #
#                            Command Argument = value pairs. mkrsrc  #
#                            command line arguments can be either    #
#                            attr=value or arg=value pairs.          #
#                                                                    #
# Global Variables Modified:                                         #
#   $Opt_Example       output   True (-e) provide example of cmdline #
#   $Opt_File_Input    output   True (-f) read rsrc data from file.  #
#   $Opt_Verify        output   True (-v) verify cmd line or file    #
#                               input is valid format.               #
#   $Opt_Node_File     output   True (-N) using a node file          #
#   $Opt_Stdin         output   True (-N) using stdin                #
#   $Verbose           output   True (-V) turn Verbose mode on.      #
#   $Trace             output   True (-T) turn Trace mode on.        #
#--------------------------------------------------------------------#
sub parse_cmd_line 
{
my $resource = "";
my $rsrc_file = ""; 
my $node_file_name = ""; 
my @cmdline_args = ();
my %opts = ();

# Process the command line...
if (!&getopts('hef:F:lN:vVT', \%opts)) {   # Gather options; if errors
    &print_usage;                       # display proper usage
    return MC_CLI_BAD_FLAG;             # return bad rc - bad flag 
}

# Always accept the -h flag regardless of other flags or operands
if (defined $opts{h}) {                 # -h, help request  
    &print_usage;                       # print usage statement
    exit(0);                            # all done with good return!
}

# mkrsrc requires at a minimum the resource class name as an 
# operand. 

# Get the arguments...
if ($#ARGV >= 0) { 
    $resource = shift @ARGV;            # user specified resource
}
else {
    # Print Missing Resource Class Name Operand message 
    printCEMsg("EMsgMCcliMissingRsrcClass");
    &print_usage;                       # display proper usage
    return MC_CLI_BAD_OPERAND;          # return bad rc - bad operand
}

# Grab all of the command arguments=value pairs (Attr=value or 
# Arg=value), that must come right after the resource class name or 
# resource handle. 
if ($#ARGV >= 0) 
{
    if (defined $opts{f} || defined $opts{F} || 
        defined $opts{e} || defined $opts{l})
    {
        printCEMsg("EMsgMCcliTooManyOperands");
        &print_usage;
        return MC_CLI_BAD_OPERAND;
    }
    else
    {
         @cmdline_args= @ARGV;           
    }
}
elsif (!defined $opts{f} && !defined $opts{F} && 
       !defined $opts{e} && !defined $opts{l}) 
{
    printCEMsg("EMsgMCcliMissingAttrAndValue");
    &print_usage;
    return MC_CLI_BAD_OPERAND;
}


# See which options/flags were used...

if (defined $opts{e}) {                 # -e, ls examples of mkrsrc
    $Opt_Example = $TRUE;
}

if (defined $opts{F}) {                     # -f, filename for rsrc data
    $opts{f} = $opts{F};                    # input rsrc file name
}

if (defined $opts{f}) {                     # -f, filename for rsrc data
    $Opt_File_Input = $TRUE;
    $rsrc_file = $opts{f};              # input rsrc file name
}

if (defined $opts{l}) {      # List any required cmd_args=data_type pairs
    $Opt_Ls_Cmd_Args = $TRUE;
}   
else
{
    $Opt_Ls_Cmd_Args = $FALSE;
}

if (defined $opts{N})                  # -N node file
{
    if ($opts{N} eq "-")
    {
        $Opt_Stdin= $TRUE;
    }
    else
    {
        $node_file_name= $opts{N};
        $node_file_name = escape_chars($node_file_name);
        $rc= check_input_file($node_file_name);
        if ($rc)
        {
            return MC_CLI_BAD_OPERAND;
        }
    }
    $Opt_Node_File= $TRUE;
}

if (defined $opts{v}) {                 # -v, verify rsrc data input
    $Opt_Verify = $TRUE;
}

if (defined $opts{T}) {                 # -T, turns tracing on 
    $Trace = $TRUE;
}

if (defined $opts{V}) {                 # -V, turns verbose mode on 
    $Verbose = $TRUE;
}

return(0, $resource, $rsrc_file, $node_file_name, \@cmdline_args);
}   # end parse_cmd_line


#--------------------------------------------------------------------#
# print_usage : print the usage statement (syntax) to stdout.        #
#   See this command's prologue syntax section for current usage.    #
#--------------------------------------------------------------------#
sub print_usage
{
printIMsg("IMsgmkrsrcUsage5");
}   # end print_usage


#--------------------------------------------------------------------#
# ls_cmd_args - Lists the online arguments and data types if any     #
#   are required for this resource class.                            #
#                                                                    #
# Parameters:                                                        #
#   $resource          in     Name of the resource class.            #
#   @$rLoArgNames      in     Reference to a list (array) of         #
#                             argument names in element order index  #
#                             for all arguments whose definitions    #
#                             are in %$rHoSDDef.                     #
#   %$rHoSDDef         in     Reference to the hash of command       #
#                             SD argument defintitions.              #
#                                                                    #
# Return:                                                            #
#   None.                                                            #
#                                                                    #
# Global References:                                                 #
#   None.                                                            #
#--------------------------------------------------------------------#
sub ls_cmd_args
{
my ($resource, $rLoArgNames, $rHoSDDef) = @_;

my ($arg_name, $data_type, $properties);

print "mkrsrc $resource ";

foreach $arg_name (@$rLoArgNames) {
    $data_type = lc $$rHoSDDef{$arg_name}{sd_dtype};
    $data_type =~ s/^ct_//;
    print "$arg_name=$data_type ";
}

print "\n";

return;
}   # end ls_cmd_args


#--------------------------------------------------------------------#
# get_sd_defs - function to get this resource's persistent           #
#   attribute SD definitions and build a hash indexible via the      #
#   attribute program name with the attributes element names and     #
#   types stored as data.                                            #
#                                                                    #
# Parameters:                                                        #
#   $resource         input   name of the resource that we wish to   #
#                             create an instance of.                 #
#   %$rHoPAttrDefs    input   Reference to the hash of Persistent    #
#                             attribute definitions.                 #
#   %$rHoSDAttrDefs   in/out  Reference to the hash of persistent    #
#                             SD attribute element definitions.      #
# Return                                                             #
#   $rc                       return code.                           #
#                                                                    #
# Global References:                                                 #
#   None.                                                            #
#--------------------------------------------------------------------#
sub get_sd_defs
{
my ($resource, $rHoPAttrDefs, $rHoSDAttrDefs) = @_;
my $rc = 0;
my @sd_attr_names = ();
my $properties = "";

# first scan through the Hash of Persistent Attributes checking
# to see if any are SDs or SDArrays and their properties are
# required or optional for define.  
my @pattr_names = keys %$rHoPAttrDefs;

foreach $attr_name (@pattr_names) {
    $dtype = $$rHoPAttrDefs{$attr_name}{at_dtype};
    $properties = $$rHoPAttrDefs{$attr_name}{at_properties};

    if ( (($dtype =~ /^CT_SD_PTR$/) || ($dtype =~ /^CT_SD_PTR_ARRAY$/)) &&
         (($properties =~ /reqd_for_define/) || ($properties =~ /option_for_define/)) )
    {
        # Add these SD attributes to array of all SD attr names
        push @sd_attr_names, $attr_name;
    } 
}

# Need to make sure each of the SDs are defined and get various info
# associated with the each persistent resource SDs elements. 

# If we found any persistent attributes that are SD get their
# definition from RMC
if (scalar(@sd_attr_names) > 0) {

    # Get the SD data and 
    # Format the Query Definition Structured Data attributes
    # and elements into a form suitable for quick look up by 
    # attribute name the for the element data_types. 
    get_sd_defs_api($resource, 0, \@sd_attr_names, $rHoSDAttrDefs);

}

return($rc);
}   # end get_sd_defs


#--------------------------------------------------------------------#
# get_sd_element_dtypes - for the specified attribute name return    #
#   an array of this SDs element's data types in element index       #
#   order.                                                           #
#                                                                    #
# Parameters:                                                        #
#   %$rHoSDAttrDefs   input   Reference to a hash of persistent      #
#                             structured data attributes.            #
#                             key  = attribute name                  #
#                             data = array of hashes, each hash      #
#                             represents one of this SDs elements    #
#   $attr_name        input   Attribute name.                        #
#                                                                    #
# Return:                                                            #
#   @sd_element_dtypess       Returns a reference to an array of     #
#                             the SD element data types in element   #
#                             index order for this attribute.        #
#                                                                    #
# Global References:                                                 #
#   None.                                                            #
#--------------------------------------------------------------------#
sub get_sd_element_dtypes {
my ($rHoSDAttrDefs, $attr_name) = @_;
my @sd_element_dtypes;
my %index_to_dtype = ();
my $element;
my $element_cnt = 0;

my @elements = keys %{ $rHoSDAttrDefs->{$attr_name} };
foreach $element (@elements) {
    $index = $rHoSDAttrDefs->{$attr_name}{$element}->{sd_index};
    $index_to_dtype{$index} = 
        $rHoSDAttrDefs->{$attr_name}{$element}->{sd_dtype};
    $element_cnt++;
}

for ($i = 0; $i < $element_cnt; $i++) {
    push @sd_element_dtypes, $index_to_dtype{$i};
}

return (@sd_element_dtypes);
}   # end get_sd_element_dtypes


#--------------------------------------------------------------------#
# process_input - process the attr=value pairs that are used to      #
#   define this resource and were input by the user on the command   #
#   line or via an input file.                                       #
#                                                                    #
# Parameters:                                                        #
#   $Opt_File_Input   input   True - input should come from file.    #
#                             False - input should come from command #
#                             line.                                  #
#   $filename         input   Name of file if $Opt_File_Input = TRUE #
#   %$rHoPAttrDefs    input   Reference to complex hash of           #
#                             persistent attribute definitions.      #
#   %$rHoSDArgDefs    input   Reference to complex hash of command   #
#                             arguments definitions for define.      #
#   @$r_cmdline       input   Reference to attr=value pairs via      #
#                             command line and ARGV.                 #
#                                                                    #
# Return:                                                            #
#   $rc                       return code.                           #
#   $rLoRsrcAttrData          reference to list/array of resources   #
#                             and each resources attr=value pairs.   #
#   $rLoRsrcArgData           reference to list/array of resources   #
#                             and each resources arg=value pairs.    #
#                                                                    #
# Global References:                                                 #
#   None.                                                            #
#--------------------------------------------------------------------#
sub process_input 
{
my ($Opt_File_Input, $filename, $rHoPAttrDefs, $rHoSDArgDefs, 
    $r_cmdline) = @_;
my $req_attr_stanza = "PersistentResourceAttributes";
my $req_arg_stanza  = "PersistentResourceArguments";
my $rc = 0;
my $rLoRsrcAttrData;
my $rLoRsrcArgData;

if ($Opt_File_Input) {
    ($rc, $rLoRsrcAttrData) = process_input_file($filename, 
        $req_attr_stanza);
    if ($rc != 0) {
        # Print Error processing input file msg
        # process_input_file will write a more detailed error message
        printEMsg("EMsgmkrsrcInputFileError", $filename);
        return(MC_CLI_USER_ERROR);
    }
    # If there are defined required command arguments get those too. 
    # but args are optional so set optional parameter 78199
    if (scalar keys(%$rHoSDArgDefs) > 0) {
        ($rc, $rLoRsrcArgData) = process_input_file($filename,
            $req_arg_stanza, 1);
        if ($rc != 0) {
            # process_input_file will write a more detailed error message 78199
            printEMsg("EMsgmkrsrcInputFileError", $filename);
            return(MC_CLI_USER_ERROR);
        }
    }
}
else {
    # Divide the command line arguments into an array of attr=value
    # pairs and an array of arg=value pairs. In parse_cmd_line we 
    # verified that all args are of form name=value or ^^. 
    my $arg_cnt = scalar @$r_cmdline;
    my %dup_names = ();
    my @cmdline_attr = ();
    my @cmdline_args = ();
    my $name;
    for (my $i = 0; $i < $arg_cnt; $i++) {
        # Preserve any ^^, which are used as resource/record 
        # separators in CT_cli_input_utils.
        if ($r_cmdline->[$i] eq "^^") {
            push @cmdline_attrs, $r_cmdline->[$i];
            if (scalar @cmdline_args > 0)  {
                push @cmdline_args, $r_cmdline->[$i];
            }
            %dup_names = ();
        }
        else {
            # Get the keyword of the keyword=value pair
            ($name, my @garbage) = split /=/, $r_cmdline->[$i]; 
            # If the command line argument is not defined as an 
            # define command argument - then treat it as an attribute.
            if (!defined $$rHoSDArgDefs{$name}) {
                push @cmdline_attrs, $r_cmdline->[$i];
            }
            # If the command line argument name is defined as both
            # a persistent attribute and as an SD, the first time you 
            # find it treat it as an attr, the second time treat it 
            # as an arg.
            elsif (defined $$rHoPAttrDefs{$name} && 
                   !defined $dup_names{$name}) {
                push @cmdline_attrs, $r_cmdline->[$i];
                $dup_names{$name} = 1;  # used it as an attr
            }
            else {
                push @cmdline_args, $r_cmdline->[$i];
            }
        }
    }   # end for 

    ($rc, $rLoRsrcAttrData) = process_cmdline_input(\@cmdline_attrs);
    if ($rc != 0) {
        # Print Command Line Error Attr=value error msg
        printEMsg("EMsgmkrsrcCmdLineError", "\"@$r_cmdline\"");
        return(MC_CLI_BAD_OPERAND);
    }

    # If there are command arguments specified get those too.
    if (scalar @cmdline_args > 0 && scalar keys(%$rHoSDArgDefs) > 0) {
        ($rc, $rLoRsrcArgData) = process_cmdline_input(\@cmdline_args);
        if ($rc != 0) {
            # Print Command Line Error Arg=value error msg
            printCEMsg("EMsgMCcliCmdLineArgError", "\"$r_cmdline\"");
            return(MC_CLI_BAD_OPERAND);
        }
    }
}

if ($Verbose) {
    my ($attribute, $value, $entry, $row_header);
    foreach $entry (@$rLoRsrcAttrData) {
        $row_header = $entry->[0];
        foreach $element (@{$entry->[1]}) {
            $attribute = $element->[0];
            $value = $element->[1];
            print "$attribute = \"$value\"\n";
        }
    }   
    foreach $entry (@$rLoRsrcArgData) {
        $row_header = $entry->[0];
        foreach $element (@{$entry->[1]}) {
            $attribute = $element->[0];
            $value = $element->[1];
            print "$attribute = \"$value\"\n";
        }
    }
}

# If there are command arguments specified, then there must be 
# one set of arguments for each set of attributes 
if ((defined $rLoRsrcArgData && scalar(@$rLoRsrcArgData) > 0) &&
    (scalar(@$rLoRsrcAttrData) != scalar(@$rLoRsrcArgData))) {
    printEMsg("EMsgmkrsrcMismatchAttrArg");
    return(MC_CLI_USER_ERROR);
}

return ($rc, $rLoRsrcAttrData, $rLoRsrcArgData);
}   # end process_input


#--------------------------------------------------------------------#
# process_nls_input - process the NLSTranslation stanza in the       #
#   resource data input file if it exists. Right now only            #
#   Predefined Conditions (not customers) should be using the        #
#   NLSTranslation Stanza.  Only persistent resource attributes      #
#   that are defined and have a data type of ct_char_ptr,            #
#   ct_char_ptr_array, ct_sd_ptr or ct_sd_ptr_array where element    #
#   specified must have a ct_char_ptr or ct_char_ptr_array data type #
#   can be translated using msgmaps and $LSMSG at this time.         #
#   Listed below is an example of an NLSTranslation stanza:          #
#   NLSTranslation::                                                 #
#       MessageMapPath = /opt/rsct/msgmaps                      #
#       MessageSet     = mkrsrc                                      #
#       MessageCat     = mccli.cat                                   #
#       PersistentResourceAttributes = {attr1,attr2,attr3.element2}  #
#          where attr 3 is an SD or SD Array                         #
#          attr1, attr2, attr3.element2 are char or char Array.      #
#                                                                    #
# Parameters:                                                        #
#   $filename         input   Name of file if $Opt_File_Input = TRUE #
#   $rHoPAttrDefs     input   Reference to a hash of the persistent  #
#                             attribute definitions for this rsrc.   #
#   $rHoSDAttrDefs    input   Reference to a hash of the SD element  #
#                             definitions for this rsrc.             #
#   $rHoNLSData       in/out  input - empty hash.                    #
#                             output - hash of NLS data.             #
#                             if the NLSTranslation stanza is used.  #
#                             Hash of NLS data and values.           #
#                             MessageMapPath => <path>               #
#                             MessageSet     => <message set name>   #
#                             MessageCat     => <message cat name>   #
#                             PersistentResourceAttributes => hash   #
#                                of attribute names.                 #
#                                                                    #
# Return:                                                            #
#   $rc                       return code.                           #
#                                                                    #
# Global References:                                                 #
#   None.                                                            #
#--------------------------------------------------------------------#
sub process_nls_input 
{
my ($filename, $rHoPAttrDefs, $rHoSDAttrDefs, $rHoNLSData) = @_;
my $rLoNLSInputData;
my $rc = 0;

# MessageMapPath, MessageSet, MessageCat and
# PersistentResourceAttributes are all required keywords in the 
# NLSTranslation stanza
my $nls_stanza = "NLSTranslation";
#my %RequiredNLSKeywords = (
#    "MessageMapPath"                => eval(CT_CHAR_PTR),
#    "MessageSet"                    => eval(CT_CHAR_PTR),
#    "MessageCat"                    => eval(CT_CHAR_PTR),
#    "PersistentResourceAttributes"  => eval(CT_CHAR_PTR_ARRAY)
#);
my %RequiredNLSKeywords = ();
$RequiredNLSKeywords{"MessageMapPath"} = "CT_CHAR_PTR";
$RequiredNLSKeywords{"MessageSet"} = "CT_CHAR_PTR";
$RequiredNLSKeywords{"MessageCat"} = "CT_CHAR_PTR";
$RequiredNLSKeywords{"PersistentResourceAttributes"} = "CT_CHAR_PTR_ARRAY";


($rc, $rLoNLSInputData) = process_input_file($filename, $nls_stanza, 1);
if ($rc != 0) {
    # Print Error processing input file msg
    # process_input_file will write a more detailed error message
    printEMsg("EMsgmkrsrcInputFileError", $filename);
    return(MC_CLI_USER_ERROR);
}

# NLSTranslation stanza is optional in the Resource Data Input
# file for mkrsrc command. If it wasn't there nothing more to
# do here - just return.         
if (!defined($rLoNLSInputData)) {
    return($rc);
}

# Read in the required keyword = value pairs from the NLSTranslation
# Stanza building the Hash of NLS Data where the key to the hash
# is the required keyword and value is the data for that keyword
$entry = $rLoNLSInputData->[0];
foreach $new_keyword (@{$entry->[1]}) {
    $keyword = $new_keyword->[0];
    if (!defined($RequiredNLSKeywords{$keyword})) {
        printEMsg("EMsgmkrsrcInvalidNLSKeyword", $keyword, $filename);
        $rc = MC_CLI_USER_ERROR;
        next;
    }
    if (!defined($rHoNLSData->{$keyword})) {
        $rHoNLSData->{$keyword} = $new_keyword->[1];
    }
}

# Make sure that all of the required keywords were supplied in 
# the NLSTranslation stanza.
@required_keywords = keys %RequiredNLSKeywords;
foreach $required_keyword (@required_keywords) {
    if (!defined($rHoNLSData->{$required_keyword})) {
        printEMsg("EMsgmkrsrcMissingNLSKeyword", $required_keyword, 
            $filename);
        $rc = MC_CLI_USER_ERROR;
    }
}

# PersistentResourceAttributes keyword should contain an array 
# of persistent attributes in the format {attr1, attr2, .., attrn}
# Convert this to a perl hash so later on we can quickly see 
# if the persistent attributes we are processing in build_resource
# in an attribute that needs to be translated.
if ($rc == 0) {
    my ($rLoAttr, $attr);
    ($rc, $rLoAttr) = convert_input_value_api(
        $RequiredNLSKeywords{PersistentResourceAttributes},
        $rHoNLSData->{PersistentResourceAttributes});
    if ($rc == 0) {
        my %temp_hash = ();
        foreach $attr (@$rLoAttr) {
            # Make sure the persistent attribute is a valid defined
            # attribute name and it has a a valid data type 
            # ct_char_ptr and ct_char_ptr_array are valid
            if (defined($rHoPAttrDefs->{$attr}) && (
                $rHoPAttrDefs->{$attr}->{at_dtype} =~ /^CT_CHAR_PTR$/ ||
                $rHoPAttrDefs->{$attr}->{at_dtype} =~ /^CT_CHAR_PTR_ARRAY$/
                )) {
                $temp_hash{$attr} = '';
            }
            else {
                ($attr, $element) = split /\./, $attr, 2;   
                # ct_sd_ptr and ct_sd_ptr_array are valid if the 
                # element specified is ct_char_ptr or ct_char_ptr_array
                if ( (defined($rHoPAttrDefs->{$attr}) && (
                    $rHoPAttrDefs->{$attr}->{at_dtype} =~ /^CT_SD_PTR$/ ||
                    $rHoPAttrDefs->{$attr}->{at_dtype} =~ /^CT_SD_PTR_ARRAY$/
                )) && 
                    (defined($rHoSDAttrDefs->{$attr}->{$element}) && (
                    $rHoSDAttrDefs->{$attr}->{$element}->{sd_dtype} =~ /^CT_CHAR_PTR$/ ||
                    $rHoSDAttrDefs->{$attr}->{$element}->{sd_dtype} =~ /^CT_CHAR_PTR_ARRAY$/
                )) ) {
                    if (defined $temp_hash{$attr}) {
                        push @{$temp_hash{$attr}}, $element; 
                    }
                    else {
                        $temp_hash{$attr} = [ ]; 
                        push @{$temp_hash{$attr}}, $element;
                    }
                }
                else {
                    printEMsg("EMsgmkrsrcNLSAttrNotValid", $attr,   
                        $filename);
                    $rc = MC_CLI_USER_ERROR;
                }
            }
        }
        $rHoNLSData->{PersistentResourceAttributes} = { %temp_hash };
    }
}

return ($rc); 
}   # end process_nls_input


#--------------------------------------------------------------------#
# build_resource - function to build up the hash of persistent attr  #
#   to be used in defining the resource. Merging the {at_name},      #
#   {at_value}, {at_dtype} all into one structure and validating     #
#   the input data as its processed.                                 #
#                                                                    #
# Parameters:                                                        #
#   $resource         input   Resource name.                         #
#   $rRsrcData        input   Reference to array of attr,value pairs.#
#   $rHoPAttrDefs     input   Reference to hash of all the required  #
#                             and optional attribute definitions     #
#                             for this resource.                     #
#   $rHoSDAttrDefs    input   Reference to hash of all the required  #
#                             and optional SD attribute definitions  #
#                             for this resource.                     #
#   $rHoNLSData       input   Reference to hash of NLS Data.         #
#                             For example:                           #
#                             MessageMapPath => </opt/rsct/..>  #
#                             MessageSet     => mkrsrc               #
#                             MessageCat     => mccli.cat            #
#                             PersistentResourceAttributes = %hash   #
#                             of attribute names that need to be     #
#                             translated.                            #
#                                                                    #
# Return:                                                            #
#   $rc                       return code.                           #
#   $rHoPAttr                 Reference complex hash of persistent   #
#                             attributes including their values.     #
#                                                                    #
# Global References:                                                 #
#   None.                                                            #
#--------------------------------------------------------------------#
sub build_resource
{
my ($resource, $rRsrcData, $rHoPAttrDefs, $rHoSDAttrDefs, 
    $rHoNLSData) = @_; 

my %HoPAttr = ();
my @required_attributes = ();
my ($new_attr, $dtype);
my $badrc = 0;
my $resource_def;

# Process all of the attr value pairs for this resource. Attr 
# value pairs should come before Arg value pairs on the command line.
foreach $new_attr (@{$rRsrcData->[1]}) {
    $attr_name = $new_attr->[0];
    # first check to make sure this is either a valid attribute name
    # or a valid command argument name.
    if (!defined($$rHoPAttrDefs{$attr_name}))
    { 
        if ($Opt_File_Input)
        {
            $resource_def= $rRsrcData->[0];
            $resource_def=~ s/^\s+//;
            $resource_def=~ s/\s+$//;
            printEMsg("EMsgmkrsrcAttrNotDefForSet3", $attr_name,
                       $resource, $resource_def);
        }
        else
        {
            printEMsg("EMsgmkrsrcAttrNotDefForSet2", $attr_name, 
                       $resource);
        }
        $badrc = MC_CLI_USER_ERROR;
        next;                   # continue validating rest of input
    }   

    # next check to make sure the value is of the right type
    # SDs require some special handling...
    $dtype = $$rHoPAttrDefs{$attr_name}{at_dtype};  
    if ( ($dtype =~ /^CT_SD_PTR$/) || ($dtype =~ /^CT_SD_PTR_ARRAY$/) ) {
        @r_sd_element_dtypes = get_sd_element_dtypes($rHoSDAttrDefs,
            $attr_name);
        ($rc, $attr_value) = convert_input_value_api($dtype, 
            $new_attr->[1], \@r_sd_element_dtypes);
    }
    else {
        ($rc, $attr_value) = convert_input_value_api($dtype, 
            $new_attr->[1]); 
    }
    if ($rc != 0) {      
        printCEMsg("EMsgMCcliBadAttrValue", $attr_name, 
            $new_attr->[1]);
        if ($badrc == 0) {$badrc = $rc; }
        next;
    }   
    %elements = ();
    $elements{at_name} = $attr_name;
    $elements{at_dtype} = $$rHoPAttrDefs{$attr_name}{at_dtype};
    $elements{at_value} = $attr_value;

    # for 2 non-array values specified in a row, save the last value 131200 131854
    if (($#$attr_value >0) && ($dtype !~ /ARRAY/) && ($dtype !~ /SD/)) {
       $elements{at_value} = $$attr_value[$#$attr_value];
    }
    
    # save original SD value
    if ( ($dtype =~ /^CT_SD_PTR$/) || ($dtype =~ /^CT_SD_PTR_ARRAY$/) ) {
       $elements{at_SD_value} = $new_attr->[1];
    }

    $HoPAttr{$attr_name} = { %elements };
}

# Build a list of the attributes that are required to define
# this resource
my @p_attr_names = keys %$rHoPAttrDefs;
foreach $attr_name (@p_attr_names) {
    $properties = $$rHoPAttrDefs{$attr_name}{at_properties};
    if ($properties =~ /reqd_for_define/ ) {
        push @required_attributes, $attr_name;
    }
}

# Make sure that all of the required attributes are being
# defined.
foreach $attr_name (@required_attributes) {
    if (!defined($HoPAttr{$attr_name})) {
        printEMsg("EMsgmkrsrcMissingReqAttr", $attr_name, $resource);
        $badrc = MC_CLI_USER_ERROR;
    }
}

# Translate any of the Persistent Attributes that were listed in 
# the NLSTranslation Stanza PersistentResourceAttributes keyword
if (defined $rHoNLSData->{PersistentResourceAttributes}) {
    $rc = translate_attr_values(\%HoPAttr, $rHoSDAttrDefs,
        $rHoNLSData);
}

return($badrc, \%HoPAttr); 
}   # end build_resource


#--------------------------------------------------------------------#
# translate_attr_values - function to translate persistent attribute #
#   values for persistent attributes that were listed in the         #
#   NLSTranslationStanza PersistenResourceAttributes keyword.        #
#   persistent attributes that have the following data types may be  #
#   translated: ct_char_ptr, ct_char_ptr_array, ct_sd_ptr and        #
#   ct_sd_ptr_array when the elements being translated are either    #
#   ct_char_ptr or ct_char_ptr_array.                                #
#                                                                    #
# Parameters:                                                        #
#   $rHoPAttr         input   Reference to hash of persistent        #
#                             attributes that we want to define.     #
#   $rHoSDAttrDefs    input   Reference to hash of all the required  #
#                             and optional SD attribute definitions  #
#                             for this resource.                     #
#   $rHoNLSData       input   Reference to hash of NLS Data.         #
#                             For example:                           #
#                             MessageMapPath => </opt/rsct/..>  #
#                             MessageSet     => mkrsrc               #
#                             MessageCat     => mccli.cat            #
#                             PersistentResourceAttributes = %hash   #
#                             of attribute names that need to be     #
#                             translated.                            #
#                                                                    #
# Return:                                                            #
#   $rc                       return code.                           #
#                                                                    #
# Global References:                                                 #
#   None.                                                            #
#--------------------------------------------------------------------#
sub translate_attr_values
{
my ($rHoPAttr, $rHoSDAttrDefs, $rHoNLSData) = @_;

my $rc = 0;
my $msg_mnemonic;                   # msg mnemonic to be translated
                                    # mnemonic & default msg are in 
                                    # message map file

my @attr_to_translate = keys %{ $rHoNLSData->{PersistentResourceAttributes} };
(scalar(@attr_to_translate) == 0) && return($rc); 
 
# temporarily change ENV MSGMAPPATH for LSMSG if need to
my $restore_msgmappath_env = $ENV{MSGMAPPATH};
if ($ENV{MSGMAPPATH} ne $rHoNLSData->{MessageMapPath}) {
    $ENV{MSGMAPPATH} = $rHoNLSData->{MessageMapPath};
}

foreach $attr_name (@attr_to_translate) {
    if (!defined($rHoPAttr->{$attr_name})) {
        next;
    }
    if ($rHoPAttr->{$attr_name}->{at_dtype} =~ /^CT_CHAR_PTR$/ ) {
        $msg_mnemonic = $rHoPAttr->{$attr_name}->{at_value};
        $rHoPAttr->{$attr_name}->{at_value} =
            `$LSMSG $rHoNLSData->{MessageSet} $rHoNLSData->{MessageCat} $msg_mnemonic`;
        $rc = $?;
        if ($rc != 0) {
            $rc = translation_error($attr_name, $msg_mnemonic,
                $restore_msgmappath_env, $rHoNLSData);
        }
    }
    elsif ($rHoPAttr->{$attr_name}->{at_dtype} =~ /^CT_CHAR_PTR_ARRAY$/ ) {
        my $i = 0;
        my $element; 
        foreach $element (@{$rHoPAttr->{$attr_name}->{at_value}}) {
            $msg_mnemonic = ($rHoPAttr->{$attr_name}->{at_value}[$i]);
            $rHoPAttr->{$attr_name}->{at_value}[$i] =
                `$LSMSG $rHoNLSData->{MessageSet} $rHoNLSData->{MessageCat} $msg_mnemonic`;
            $rc = $?;
            if ($rc != 0) {
                $rc = translation_error($attr_name, $msg_mnemonic,
                    $restore_msgmappath_env, $rHoNLSData);
            }

            $i++;
        }
    }
    elsif ($rHoPAttr->{$attr_name}->{at_dtype} =~ /^CT_SD_PTR$/ ) {
        my $sd_element;
        foreach $sd_element (@{$rHoNLSData->{PersistentResourceAttributes}->{$attr_name}}) {
            my $sd_element_index = 
                $rHoSDAttrDefs->{$attr_name}->{$sd_element}{sd_index};
            $msg_mnemonic = 
                $rHoPAttr->{$attr_name}{at_value}->[$sd_element_index]->{value};
            $rHoPAttr->{$attr_name}{at_value}->[$sd_element_index]->{value} = 
                `$LSMSG $rHoNLSData->{MessageSet} $rHoNLSData->{MessageCat} $msg_mnemonic`;
            $rc = $?;
            if ($rc != 0) {
                $rc = translation_error($attr_name, $msg_mnemonic,
                    $restore_msgmappath_env, $rHoNLSData);
            }
        }
    }
    elsif ($rHoPAttr->{$attr_name}->{at_dtype} =~ /^CT_SD_PTR_ARRAY$/ ) {
        my $sd_element;
        foreach $sd_element (@{$rHoNLSData->{PersistentResourceAttributes}->{$attr_name}}) {
            my $sd_element_index = 
                $rHoSDAttrDefs->{$attr_name}->{$sd_element}{sd_index};

            my $num_array_elements = 
                scalar(@{$rHoPAttr->{$attr_name}->{at_value}}); 
            for (my $i = 0; $i < $num_array_elements; $i++) {
                $msg_mnemonic = $rHoPAttr->{$attr_name}{at_value}->[$i]->[$sd_element_index]->{value};
                $rHoPAttr->{$attr_name}{at_value}->[$i]->[$sd_element_index]->{value} = 
                    `$LSMSG $rHoNLSData->{MessageSet} $rHoNLSData->{MessageCat} $msg_mnemonic`;
                $rc = $?;
                if ($rc != 0) {
                    $rc = translation_error($attr_name, $msg_mnemonic,
                        $restore_msgmappath_env, $rHoNLSData);
                }
                # change it in original value too
                $rHoPAttr->{$attr_name}{at_SD_value} =~ s/$msg_mnemonic/$rHoPAttr->{$attr_name}{at_value}->[$i]->[$sd_element_index]->{value}/;
            }
        }
    }
    else {
    # This should never happen - but print warning just in case. 
    # NLS Translation only supported internal to IBM.
        print STDERR "mkrsrc - translation of data type: ", 
            $rHoPAttr->{$attr_name}->{at_dtype}, " is not supported.\n";
    }
}   # end foreach

# restore the original messagemappath for normal error messages
if ($ENV{MSGMAPPATH} ne $rHoNLSData->{MessageMapPath}) {
    $ENV{MSGMAPPATH} = $restore_msgmappath_env;
}

return $rc;
}   # end translate_attr_value


#--------------------------------------------------------------------#
# translation_error - convenience function to write the Translation  #
#   Eror Message. Easier to have a function to do this since may     #
#   to alter the MSGMAPPATH environment variable before writing the  #
#   message and then resetting the environment variable.             #
#                                                                    #
# Parameters:                                                        #
#   $attr_name        input   Name of the persistent attribute whose #
#                             value we are having problems           #
#                             translating.                           #
#   $msg_mnemonic     input   The message mnemonic that should be    #
#                             found in the specific message map.     #
#   $restore_msgmappath input The message map path where mkrsrc      #
#                             msgmap file is located.                #
#   %$rHoNLSData      input   Reference to complex hash associated   #
#                             with the data in the                   #
#                             NLSTranslation stanza.                 #
#                                                                    #
# Return:                                                            #
#   MC_CLI_USER_ERROR         This function only gets called when    #
#                             there is translation problem.          #
#                                                                    #
# Global References:                                                 #
#   None.                                                            #
#--------------------------------------------------------------------#
sub translation_error 
{
my ($attr_name, $msg_mnemonic, $restore_msgmappath, $rHoNLSData) = @_;

if ($ENV{MSGMAPPATH} ne $restore_msgmappath) {
    $ENV{MSGMAPPATH} = $restore_msgmappath; 
}

my ($msgcatprefix, $dummy) = split /\./, $rHoNLSData->{MessageCat};
my $msgmap = $rHoNLSData->{MessageMapPath} . "/" . $msgcatprefix . 
    "." . $rHoNLSData->{MessageSet} . ".map";

printEMsg("EMsgmkrsrcTranslationError", $attr_name, "$msg_mnemonic",
    $msgmap, $rHoNLSData->{MessageCat});

if ($ENV{MSGMAPPATH} ne $restore_msgmappath) {
    $ENV{MSGMAPPATH} = $rHoNLSData->{MessageMapPath};
}

return(MC_CLI_USER_ERROR);
}   # end translation_error


#--------------------------------------------------------------------#
# define_resource - function to call the mkrsrc-api command to       #
#   create one or more resources.                                    #
#                                                                    #
# Parameters:                                                        #
#   @$parms           input   Reference to parameter strings to send #
#                             to mkrsrc-api.                         #
#   $node_file        input   Name of the node list file, if used.   #
#                                                                    #
# Return:                                                            #
#   $rc                       return code.                           #
#                                                                    #
# Global References:                                                 #
#   Trace             input   Trace call & return of extension.      #
#   Verbose           input   Print newly defined rsrc handle.       #
#--------------------------------------------------------------------#
sub define_resource 
{
my ($parms, $node_file) = @_;
my $rc = 0;
my $i = 0;
my @mk_out = ();
my $parmlen = 0;

# check if -f or -F was used for file input
# -F means continue on error

# get the total length for the command to see if the command buffer will be exceeded
for  ($i=0; $i<=$#$parms;$i++){
   $parmlen += length($$parms[$i]);
}

# add in various other things to the length
$parmlen += length($CTBINDIR) + length($DELIMITER)*2 + $#$parms + 50;

# add in the length of the file name
if ($Opt_Stdin) {
   $node_file = read_from_Stdin();
}

if ($Opt_Node_File) {
   $parmlen += length($node_file);
}

# decide how to call mkrsrc-api based on the command length
if ($parmlen > $CMD_LIMIT) {
   # use mkrsrc-api with file option
   $rc = mkrsrcapi_file($parms, $node_file);
}
else {
   # use mkrsrc-api using the command buffer
   $rc = mkrsrcapi_cmdline($parms, $node_file);
}

return $rc;
}   # end define_resource


#--------------------------------------------------------------------#
# setup_mkrsrcapi - function to add a parameter specification to be  #
#   used later for mkrsrc-api.                                       #
#                                                                    #
# Parameters:                                                        #
#   $mkrsrcapi_parm   in/out  Name of the string variable that has   #
#                             any previous resource definition.      #
#   $rsrc_class       input   Name of the resource class to which we #
#                             want to define a new resource.         #
#   %$rHoAttr         input   Reference to complex hash of attribute #
#                             names and value pairs.                 #
#   @$rLoSDArgs       input   Reference to a list of of SD Command   #
#                             Arguments (if any).                    #
#                                                                    #
# Return:                                                            #
#   $rc                       return code.                           #
#                                                                    #
# Global References:                                                 #
#   Trace             input   Trace call & return of extension.      #
#   Verbose           input   Print newly defined rsrc handle.       #
#--------------------------------------------------------------------#
sub setup_mkrsrcapi
{
my ($mkrsrcapi_parm, $rsrc_class, $rHoAttr, $rLoSDArgs) = @_;
my $newparms= "";
my $tmpparms= "";
my $i=0;
my $j=0;
my $k=0;
my $m=0;
my $comma = "";
my $incomma = "";

#$Verbose && printIMsg("IMsgmkrsrcDefiningRsrc", $rsrc_class);
#$Trace && print STDERR "Calling mkrsrc-api\n";

# format being created:
# ClassName[::<AttrName>::<AttrValue]...[::[::<ArgName>::<ArgValue>]...]

# start new parameter list with resource class
$newparms = $rsrc_class;

# add regular attributes and values
my @attr_list = keys %$rHoAttr;
foreach $attr (@attr_list) {
   if ( $$rHoAttr{$attr}{at_dtype} =~ /^CT_SD_PTR$/ ) {
      #$newparms .= $DELIMITER . $attr . $DELIMITER . $$rHoAttr{$attr}{at_SD_value};
      $tmpparms = "[";
      $comma = "";

      # build SD from converted elements in hashes
      for ($j=0; $j <= $#{$$rHoAttr{$attr}{at_value}}; $j++) {

          # see if the element is an array or not
          if (${${$$rHoAttr{$attr}{at_value}}[$j]}{type} =~ /ARRAY/) {

             # process array elemets
             $tmpparms .= $comma . "{";
             $incomma = "";
             for ($k=0; $k <= $#{${${$$rHoAttr{$attr}{at_value}}[$j]}{value}}; $k++) {
                $tmpparms .= $incomma . ${${${$$rHoAttr{$attr}{at_value}}[$j]}{value}}[$k];
                $incomma = ",";
             }
             $tmpparms .= "}";
          }

          # not an array, get elements
          else {
             $tmpparms .= $comma . ${${$$rHoAttr{$attr}{at_value}}[$j]}{value};
             $comma = ",";
          }
      }
      $tmpparms .= "]";
      $newparms .= $DELIMITER . $attr . $DELIMITER . $tmpparms;

   }
   elsif ( $$rHoAttr{$attr}{at_dtype} =~ /^CT_SD_PTR_ARRAY$/ ) {
      #$newparms .= $DELIMITER . $attr . $DELIMITER . $$rHoAttr{$attr}{at_SD_value};
      $tmpparms = "{";
      # build SD array from converted elements in arrays of hashes
      # first the array of hash arrays (1 for each SD in the array)
      for ($j=0; $j <= $#{$$rHoAttr{$attr}{at_value}}; $j++) {
          $tmpparms .= "[";
          $comma = "";

          # get the values of each SD
          for ($k=0; $k <= $#{${$$rHoAttr{$attr}{at_value}}[$j]}; $k++) {

              # see if it's an array
              if (${${$$rHoAttr{$attr}{at_value}}[$j][$k]}{type} =~ /ARRAY/) {

                  # process array elemets
                  $tmpparms .= $comma . "{";
                  $incomma = "";
                  for ($m=0; $m <= $#{${${$$rHoAttr{$attr}{at_value}}[$j][$k]}{value}}; $m++) {
                      $tmpparms .= $incomma . ${${${$$rHoAttr{$attr}{at_value}}[$j][$k]}{value}}[$m];
                      $incomma = ",";
                  }
                  # finish off the array
                  $tmpparms .= "}";
              }
              else {
                  # not an array, get the value
                  $tmpparms .= $comma . ${${$$rHoAttr{$attr}{at_value}}[$j][$k]}{value};
                  $comma = ",";
              }
          }
 
          # mark the end of an SD array element
          if ($j == $#{$$rHoAttr{$attr}{at_value}}) {$tmpparms .= "]";}
          else {$tmpparms .= "],";}
      }
      # mark the end of the SD array
      $tmpparms .= "}";

      # assign the final value
      $newparms .= $DELIMITER . $attr . $DELIMITER . $tmpparms;
   }
   elsif ( $$rHoAttr{$attr}{at_dtype} =~ /ARRAY/ ) {
      $comma = "";
      $tmpparms = "{";
      $i = scalar(@{$rHoAttr->{$attr}->{at_value}});
      for ($j=0; $j<$i; $j++){
          $tmpparms .= $comma . $rHoAttr->{$attr}->{at_value}[$j];
          $comma = ",";
      }
      $tmpparms .= "}";
      $comma = "";
      
      $newparms .= $DELIMITER . $attr . $DELIMITER . $tmpparms;
      
   }
   elsif ( $$rHoAttr{$attr}{at_dtype} =~ /^CT_CHAR_PTR$/ ) {
      # drop the outside double quotes, if any
      if (  ( $$rHoAttr{$attr}{at_value} =~ /^\"/ ) && ( $$rHoAttr{$attr}{at_value} =~ /\"$/ ) ) {
         $$rHoAttr{$attr}{at_value} =~ s/^\"//;
         $$rHoAttr{$attr}{at_value} =~ s/\"$//;
      }
      $newparms .= $DELIMITER . $attr . $DELIMITER . $$rHoAttr{$attr}{at_value};
   }
   else {
      $newparms .= $DELIMITER . $attr . $DELIMITER . $$rHoAttr{$attr}{at_value};
   }
}
# check for any null attribute values
# should be ok but mkrsrc-api doesn't like it now
$newparms =~ s/${DELIMITER}${DELIMITER}/${DELIMITER}''${DELIMITER}/g;
$newparms =~ s/${DELIMITER}$/${DELIMITER}''/;

$comma = "";
# process any command options (arguments)
if ($#{$rLoSDArgs} >=0) {
   # use double delimiters to show args next
   $newparms .= $DELIMITER;
   for (my $j=0; $j<=$#$rLoSDArgs; $j++) {
      if ( ${$$rLoSDArgs[$j]}{type} =~ /ARRAY/ ) {
         $tmpparms = "{";
         $i = scalar (@{$$rLoSDArgs[$j]->{value}});
         for (my $k=0; $k<$i; $k++){
             $tmpparms .= $comma . ${$$rLoSDArgs[$j]->{value}}[$k];
             $comma = ",";
         }
         $tmpparms .= "}";
         $comma = "";
      
         $newparms .= $DELIMITER . $$rLoSDArgs[$j]->{name} . $DELIMITER . $tmpparms;
      
      }
      else {
         $newparms .= $DELIMITER . $$rLoSDArgs[$j]->{name} . $DELIMITER . $$rLoSDArgs[$j]->{value};
      }
   }
}

# going to put double quotes around the whole thing so 
# escape any inner quotes
##$newparms =~ s/\\/\\\\/g;
##$newparms =~ s/\"/\\\"/g;
#$newparms = escape_chars($newparms);
#$newparms = "\"" . $newparms . "\"";

# append the new parameters to the existing one
$i =  $#$mkrsrcapi_parm;
#if ( ($i<0) || (length($$mkrsrcapi_parm[$i]) > $CMD_LIMIT) ) {
#    $$mkrsrcapi_parm[$i+1] .= " " . $newparms;
#}
#else {
#    $$mkrsrcapi_parm[$i] .= " " . $newparms;
#}

# create a new entry for this resource definition
$$mkrsrcapi_parm[$i+1] .= $newparms;
 
return (@$mkrsrcapi_parm);

}   # end setup_mkrsrcapi


#--------------------------------------------------------------------#
# mkrsrcapi_file - function to call the mkrsrc-api command after     #
#   building an input file conataining the resource definition.      #
#   This is called when the command line buffer is not big enough to #
#   handle all of the command input to be processed.                 #
#                                                                    #
# Parameters:                                                        #
#   $@parms           input   Reference to parameter strings to send #
#                             to mkrsrc-api.                         #
#   $node_file        input   Node list file, if used.               #
#                                                                    #
# Return:                                                            #
#   $rc                       return code.                           #
#                                                                    #
# Global References:                                                 #
#   Trace             input   Trace calls & returns.                 #
#   Verbose           input   Print some extra details.              #
#--------------------------------------------------------------------#
sub mkrsrcapi_file
{
my ($parms, $node_file) = @_;
my $rc = 0;
my $i = 0;
my @mk_out = ();
my @cmd_out = ();
my $mytmpdir = "";
my $cttmpdir_exit = 0;
my $mk_file = "";
my $mk_time = 0;       
my $mk_pid = $$;       
my $file_error = "";
my $node_file_opt = "";

# create the file name to be used
$mk_time = time();
$mytmpdir = `/opt/rsct/bin/cttmpdir`;
chomp $mytmpdir;
$cttmpdir_exit = $?;
if ($cttmpdir_exit != 0) {
	$mytmpdir = "/tmp";
}
$mk_file = "$mytmpdir/mkrsrc_file_input.${mk_pid}.${mk_time}";

# add a new line character to each line to go into the file 
for ($i=0; $i<=$#$parms; $i++) {
   $$parms[$i] .= "\n";
}

if ($main::Trace) { print STDERR "Creating $mk_file to store resource information.\n";}

if (open (MKFILE, ">$mk_file") ) {

   if (!(print MKFILE @$parms)) {
      # get the error
      $file_error = $!;

      # print error message and exit
      &printEMsg("EMsgmkrsrcTempFileError",$file_error);

      # try to delete the temp file in case it was created
      @cmd_out = `/bin/rm $mk_file 2>&1`;
      exit(MC_CLI_USER_ERROR);
   }

   if (!(close(MKFILE))) {
      # get the error
      $file_error = $!;

      # print error message and exit
      &printEMsg("EMsgmkrsrcTempFileError",$file_error);

      # try to delete the temp file in case it was created
      @cmd_out = `/bin/rm $mk_file 2>&1`;
      exit(MC_CLI_USER_ERROR);
   }
}

# process error from open
else {
   # get the error
   $file_error = $!;

   # print error message and exit
   &printEMsg("EMsgmkrsrcTempFileError",$file_error);

   # try to delete the temp file in case it was created
   @cmd_out = `/bin/rm $mk_file 2>&1`;
   exit(MC_CLI_USER_ERROR);
}

if ($main::Trace) { print STDERR "Calling mkrsrc-api:\n";
   print STDERR "mkrsrc-api parameters:";
   print STDERR "@$parms\n";
}

# see if node file used
if ($Opt_Node_File) {
   $node_file_opt = " -N ${node_file} ";
}

# call mkrsrc-api. -F causes the input file to be deleted
@mk_out = `$CTBINDIR/mkrsrc-api $node_file_opt -I $DELIMITER -D $DELIMITER -F $mk_file 2>&1`;

# capture the return code from mkrsrc-api
$rc = $?;
$rc = process_exit_code($rc);

if ($main::Trace) { print STDERR "mkrsrc-api results:\n";
   print STDERR "mkrsrc-api returned $rc \n";
   print STDERR "@mk_out";
}

# show any errors if there was a bad rc
if ($rc != 0) {
   process_api_error($DELIMITER,$rc,@mk_out);
}

# delete the temp file, just in case
@cmd_out = `/bin/rm $mk_file 2>&1`;

# delete the temp Stdin file if used
if ($Opt_Stdin) {
   unlink($node_file);
}

return $rc;
}   # end mkrsrcapi_file


#--------------------------------------------------------------------#
# mkrsrcapi_cmdline - function to call the mkrsrc-api command after  #
#   building a command string to pass to the command.                #
#                                                                    #
# Parameters:                                                        #
#   $@parms           input   Reference to parameter strings to send #
#                             to mkrsrc-api.                         #
#   $node_file        input   Node list file name, if used.          #
#                                                                    #
# Return:                                                            #
#   $rc                       return code.                           #
#                                                                    #
# Global References:                                                 #
#   Trace             input   Trace calls & returns.                 #
#   Verbose           input   Print some extra details.              #
#--------------------------------------------------------------------#
sub mkrsrcapi_cmdline
{
my ($parms, $node_file) = @_;
my $parms_cmd = "";
my $args = "";
my $rc = 0;
my @mk_out = ();
my $node_file_opt = "";

# create the command string 
foreach $args (@$parms) {
   # need quotes around the whole thing so first escape an inner ones 
   $args = escape_chars($args);
   $args = "\"" . $args . "\"";

   $parms_cmd .= " " . $args;
}

# see if node file used
if ($Opt_Node_File) {
   $node_file_opt = " -N ${node_file} ";
}

if ($main::Trace) { print STDERR "Calling mkrsrc-api:\n";
   print STDERR "mkrsrc-api parameters:";
   print STDERR "$parms_cmd\n";
}

@mk_out = `$CTBINDIR/mkrsrc-api $node_file_opt -I $DELIMITER -D $DELIMITER $parms_cmd 2>&1`;

# capture the return code from mkrsrc-api
$rc = $?;
$rc = process_exit_code($rc);

if ($main::Trace) { print STDERR "mkrsrc-api results:\n";
   print STDERR "mkrsrc-api returned $rc \n";
   print STDERR "@mk_out";
}

# show any errors if there was a bad rc
if ($rc != 0) {
   process_api_error($DELIMITER,$rc,@mk_out);
}

# delete the temp Stdin file if used
if ($Opt_Stdin) {
   unlink($node_file);
}

return $rc;
}   # end mkrsrcapi_cmdline


#--------------------------------------------------------------------#
# ls_mkrsrc_example - Lists two examples of valid cmd line input     #
#   for mkrsrc command for the specified resource. Required          #
#   attributes are listed first, required and optional attributes    #
#   are listed next.                                                 #
#                                                                    #
# Parameters:                                                        #
#   $resource         in      Name of the resource class.            #
#   %$rHoPAttrDefs    in      Reference to the hash of persistent    #
#                             attribute definitions.                 #
#   %$rHoSDArgDefs    in      Reference to the hash of argument      #
#                             definitions for define resource.       #
#                                                                    #
# Return:                                                            #
#   None.                                                            #
#                                                                    #
# Global References:                                                 #
#   None.                                                            #
#--------------------------------------------------------------------#
sub ls_mkrsrc_example
{
my ($resource, $rHoPAttrDefs, $rHoSDArgDefs) = @_;
my ($attribute, $argument, $data_type, $properties);

# first list the attributes that are required for define
printIMsg("IMsgmkrsrcExReqdAttrs");

print "mkrsrc $resource ";
foreach $attribute (keys %$rHoPAttrDefs) {
     $properties = $$rHoPAttrDefs{$attribute}{at_properties};
     if ( $properties =~ /reqd_for_define/ )
        {
        $data_type = lc $$rHoPAttrDefs{$attribute}{at_dtype}; 
        $data_type =~ s/^ct_//;
        print "$attribute=$data_type "; 
        }
}
print "\n\n";

# next list required and optional attributes and arguments
printIMsg("IMsgmkrsrcExReqdOptAttrsCmdArgs");
print "mkrsrc $resource ";

# required for define...
foreach $attribute (keys %$rHoPAttrDefs) {
    $properties = $$rHoPAttrDefs{$attribute}{at_properties};
     if ( $properties =~ /reqd_for_define/ )
        {
        $data_type = lc $$rHoPAttrDefs{$attribute}{at_dtype}; 
        $data_type =~ s/^ct_//;
        print "$attribute=$data_type "; 
        }
}
# ... and optional for define
foreach $attribute (keys %$rHoPAttrDefs) {
    $properties = $$rHoPAttrDefs{$attribute}{at_properties};
     if ( $properties =~ /option_for_define/ )
        {
        $data_type = lc $$rHoPAttrDefs{$attribute}{at_dtype}; 
        $data_type =~ s/^ct_//;
        print "$attribute=$data_type "; 
        }
}
# ... and the optional argument=value pairs
foreach $argument (keys %$rHoSDArgDefs) {
    $data_type = lc $$rHoSDArgDefs{$argument}{sd_dtype};
    $data_type =~ s/^ct_//;
    print "$argument=$data_type "; 
}
print "\n";

}   # end ls_mkrsrc_example


#--------------------------------------------------------------------#
# error_check - checks the return code from the RMC function and     #
#   the error response return code.  If an error is detected         #
#   appropriate error messages will be displayed.                    #
#                                                                    #
# Parameters:                                                        #
#   $rmc_function     in      Name of the rmc function that was      #
#                             called and whose error code we are     #
#                             checking.                              #
#   $rmc_class        in      The rmc class name.                    #
#   $response         in      RMC response.                          #
#   $rmc_rc           in      The rmc function return code.          #
#   $error            in      The error response.                    #
#                                                                    #
# Return:                                                            #
#   $rc                       return code.                           #
#                                                                    #
# Global References:                                                 #
#   None.                                                            #
#--------------------------------------------------------------------#
sub error_check
{
my ($rmc_function, $rmc_class, $response, $rmc_rc, $error) = @_;

my $rc = 0;
my $err_rc = $error->errnum();

if ($rmc_rc != 0) {
    printEMsg("EMsgmkrsrcMkRsrcError", $rmc_class);
    my $rmc_rc_hex = sprintf "0x%8.8lx", $rmc_rc;
    printCEMsg("EMsgMCcliMCFunctionFailure", $rmc_function,
        $rmc_rc, $rmc_rc_hex);
    $rc = MC_CLI_RMC_ERROR;
    return $rc;
}

# Check the errnum in each of the RMC responses
for (my $r = 0; $r < $response->array_count; $r++) {
    # get the error that goes with the specific response
    if ($r > 0) {
        $response->error($error, $r);
        $err_rc = $error->errnum();
    }
    if ($err_rc != 0) {
        if ($err_rc == RMC_ECLASSNOTDEFINED) {
            printCEMsg("EMsgMCcliClassNotDef", $rmc_class);
            $rc = MC_CLI_USER_ERROR;
        }
        elsif ($err_rc == RMC_EACCESS) {
            print STDERR $error->error_msg;
            $rc = MC_CLI_USER_ERROR;
        }
        else {
            printEMsg("EMsgmkrsrcMkRsrcError", $rmc_class);
            my $err_rc_hex = sprintf "0x%8.8lx", $err_rc;
            printCEMsg("EMsgMCcliMCFunctionFailure", $rmc_function,
                $err_rc, $err_rc_hex);
            print STDERR $error->error_msg; 
            $rc = MC_CLI_RMC_ERROR;
        }
    }   # end if
}   # end for

return $rc;
}   # end error_check