14d942998SMichael Walsh#!/usr/bin/wish
24d942998SMichael Walsh
34d942998SMichael Walsh# This file provides shell command procedures cmd_fnc and t_cmd_fnc.
44d942998SMichael Walsh
54d942998SMichael Walshmy_source [list print.tcl]
64d942998SMichael Walsh
74d942998SMichael Walsh
84d942998SMichael Walshproc cmd_fnc { cmd_buf { quiet {} } { test_mode {} } { print_output {} }\
94d942998SMichael Walsh  { show_err {} } { ignore_err {} } { acceptable_shell_rcs {} } } {
104d942998SMichael Walsh
11*410b1787SMichael Walsh  # Run the given command in a shell and return the shell return code and the output as a 2 element list.
124d942998SMichael Walsh
134d942998SMichael Walsh  # Example usage:
144d942998SMichael Walsh  # set result [cmd_fnc "date"].
154d942998SMichael Walsh
164d942998SMichael Walsh  # Example output:
174d942998SMichael Walsh
184d942998SMichael Walsh  # #(CST) 2018/01/17 16:23:28.951643 -    0.001086 - Issuing: date
194d942998SMichael Walsh  # Mon Feb 19 10:12:10 CST 2018
204d942998SMichael Walsh  # result:
214d942998SMichael Walsh  #   result[0]:                                      0x00000000
22*410b1787SMichael Walsh  #   result[1]:                                      Mon Feb 19 10:12:10 CST 2018
234d942998SMichael Walsh
24*410b1787SMichael Walsh  # Note: Because of the way this procedure processes parms, the user can specify blank values as a way of
25*410b1787SMichael Walsh  # skipping parms.  In the following example, the caller is indicating that they wish to have quiet and
264d942998SMichael Walsh  # test_mode take their normal defaults but have print_output be 0.:
274d942998SMichael Walsh  # cmd_fnc "date" "" "" 0
284d942998SMichael Walsh
294d942998SMichael Walsh  # Description of argument(s):
304d942998SMichael Walsh  # cmd_buf                         The command string to be run in a shell.
31*410b1787SMichael Walsh  # quiet                           Indicates whether this procedure should run the print_issuing() procedure
32*410b1787SMichael Walsh  #                                 which prints "Issuing: <cmd string>" to stdout.  The default value is 0.
33*410b1787SMichael Walsh  # test_mode                       If test_mode is set, this procedure will not actually run the command.
34*410b1787SMichael Walsh  #                                 If print_output is set, it will print "(test_mode) Issuing: <cmd string>"
35*410b1787SMichael Walsh  #                                 to stdout.  The default value is 0.
36*410b1787SMichael Walsh  # print_output                    If this is set, this procedure will print the stdout/stderr generated by
37*410b1787SMichael Walsh  #                                 the shell command.  The default value is 1.
38*410b1787SMichael Walsh  # show_err                        If show_err is set, this procedure will print a standardized error report
39*410b1787SMichael Walsh  #                                 if the shell command returns non-zero.  The default value is 1.
40*410b1787SMichael Walsh  # ignore_err                      If ignore_err is set, this procedure will not fail if the shell command
41*410b1787SMichael Walsh  #                                 fails.  However, if ignore_err is not set, this procedure will exit 1 if
42*410b1787SMichael Walsh  #                                 the shell command fails.  The default value is 1.
43*410b1787SMichael Walsh  # acceptable_shell_rcs            A list of acceptable shell rcs.  If the shell return code is found in
44*410b1787SMichael Walsh  #                                 this list, the shell command is considered successful.  The default value
45*410b1787SMichael Walsh  #                                 is {0}.
464d942998SMichael Walsh
474d942998SMichael Walsh  # Set defaults.
484d942998SMichael Walsh  set_var_default quiet [get_stack_var quiet 0 2]
494d942998SMichael Walsh  set_var_default test_mode 0
504d942998SMichael Walsh  set_var_default print_output 1
514d942998SMichael Walsh  set_var_default show_err 1
524d942998SMichael Walsh  set_var_default ignore_err 1
534d942998SMichael Walsh  set_var_default acceptable_shell_rcs 0
544d942998SMichael Walsh
554d942998SMichael Walsh  qpissuing $cmd_buf $test_mode
564d942998SMichael Walsh
574d942998SMichael Walsh  if { $test_mode } { return [list 0 ""] }
584d942998SMichael Walsh
594d942998SMichael Walsh  set shell_rc 0
604d942998SMichael Walsh
614d942998SMichael Walsh  if { [ catch {set out_buf [eval exec bash -c {$cmd_buf}]} result ] } {
624d942998SMichael Walsh    set out_buf $result
634d942998SMichael Walsh    set shell_rc [lindex $::errorCode 2]
644d942998SMichael Walsh  }
654d942998SMichael Walsh
664d942998SMichael Walsh  if { $print_output } { puts "${out_buf}" }
674d942998SMichael Walsh
684d942998SMichael Walsh  # Check whether return code is acceptable.
694d942998SMichael Walsh  if { [lsearch -exact $acceptable_shell_rcs ${shell_rc}] == -1 } {
704d942998SMichael Walsh    # The command failed.
714d942998SMichael Walsh    append error_message "The prior shell command failed.\n"
724d942998SMichael Walsh    append error_message [sprint_var shell_rc "" "" 1]
734d942998SMichael Walsh    if { $acceptable_shell_rcs != 0 } {
74*410b1787SMichael Walsh      # acceptable_shell_rcs contains more than just a single element equal to 0.
754d942998SMichael Walsh      append error_message "\n"
764d942998SMichael Walsh      append error_message [sprint_list acceptable_shell_rcs "" "" 1]
774d942998SMichael Walsh    }
784d942998SMichael Walsh    if { ! $print_output } {
794d942998SMichael Walsh      append error_message "out_buf:\n${out_buf}"
804d942998SMichael Walsh    }
814d942998SMichael Walsh    if { $show_err } {
824d942998SMichael Walsh      print_error_report $error_message
834d942998SMichael Walsh    }
844d942998SMichael Walsh
854d942998SMichael Walsh    if { ! $ignore_err } {
864d942998SMichael Walsh      exit 1
874d942998SMichael Walsh    }
884d942998SMichael Walsh
894d942998SMichael Walsh  }
904d942998SMichael Walsh
914d942998SMichael Walsh  return [list $shell_rc $out_buf]
924d942998SMichael Walsh
934d942998SMichael Walsh}
944d942998SMichael Walsh
954d942998SMichael Walsh
964d942998SMichael Walshproc t_cmd_fnc { args } {
974d942998SMichael Walsh
98*410b1787SMichael Walsh  # Call cmd_fnc with test_mode equal to the test_mode setting found by searching up the call stack.  See
99*410b1787SMichael Walsh  # cmd_fnc (above) for details for all other arguments.
1004d942998SMichael Walsh
101*410b1787SMichael Walsh  # We wish to obtain a value for test_mode by searching up the call stack.  This value will govern whether
102*410b1787SMichael Walsh  # the command specified actually gets executed.
1034d942998SMichael Walsh  set_var_default test_mode [get_stack_var test_mode 0 2]
10450146219SMichael Walsh
105*410b1787SMichael Walsh  # Since we wish to manipulate the value of test_mode, which is the third positional parm, we must make
106*410b1787SMichael Walsh  # sure we have at least 3 parms.  We will now append blank values to the args list as needed to ensure that
107*410b1787SMichael Walsh  # we have the minimum 3 parms.
10850146219SMichael Walsh  set min_args 3
10950146219SMichael Walsh  for {set ix [llength $args]} {$ix < $min_args} {incr ix} {
11050146219SMichael Walsh    lappend args {}
11150146219SMichael Walsh  }
11250146219SMichael Walsh
113*410b1787SMichael Walsh  # Now replace the caller's test_mode value with the value obtained from the call stack search.  It does
114*410b1787SMichael Walsh  # not matter what value is specified by the caller for test_mode.  It will be replaced.  The whole point of
115*410b1787SMichael Walsh  # calling t_cmd_fnc is to allow it to set the test_mode.
1164d942998SMichael Walsh  set args [lreplace $args 2 2 $test_mode]
1174d942998SMichael Walsh
1184d942998SMichael Walsh  return [cmd_fnc {*}$args]
1194d942998SMichael Walsh
1204d942998SMichael Walsh}
121