###############################################################################
#
# exec.eagle --
#
# Extensible Adaptable Generalized Logic Engine (Eagle)
# Eagle Execute Package File
#
# Copyright (c) 2007-2012 by Joe Mistachkin.  All rights reserved.
#
# See the file "license.terms" for information on usage and redistribution of
# this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: $
#
###############################################################################

#
# NOTE: Use our own namespace here because even though we do not directly
#       support namespaces ourselves, we do not want to pollute the global
#       namespace if this script actually ends up being evaluated in Tcl.
#
namespace eval ::Eagle {
  #
  # NOTE: This procedure executes a native Tcl or Eagle sub-shell using the
  #       specified arguments and returns the captured output, verbatim.
  #
  proc execShell { options args } {
    #
    # NOTE: Start out with just the base [exec] command.
    #
    set command [list exec]

    #
    # NOTE: Add options for the [exec] command, if any.
    #
    if {[llength $options] > 0} then {
      eval lappend command $options
    }

    #
    # NOTE: Always add the end-of-options marker.
    #
    lappend command --

    #
    # NOTE: Check for native Tcl and Mono because this impacts how the
    #       shell executable name is determined.
    #
    if {[isEagle] && [isMono]} then {
      #
      # HACK: Assume that Mono is somewhere along the PATH.
      #
      lappend command mono \
          [appendArgs \" [file nativename [info nameofexecutable]] \"]
    } else {
      lappend command [info nameofexecutable]

      #
      # HACK: When running on .NET Core, we need to insert the "exec"
      #       command line argument followed by our assembly name.
      #
      if {[isEagle] && [isDotNetCore]} then {
        lappend command exec

        lappend command [appendArgs \" \
            [file nativename [lindex [info assembly true] 1]] \"]
      }
    }

    #
    # NOTE: If possible, check if the current interpreter has security
    #       enabled; if so, add the appropriate command line option for
    #       the sub-process.
    #
    if {[isEagle] && [llength [info commands object]] > 0} then {
      if {[catch {
        object invoke -flags +NonPublic Interpreter.GetActive HasSecurity
      } security] == 0 && $security} then {
        lappend command -security true
      }
    }

    #
    # NOTE: Add command line arguments to the shell command, if any.
    #
    if {[llength $args] > 0} then {
      eval lappend command $args
    }

    #
    # NOTE: Finally, execute the resulting [exec] command in the context
    #       of the caller, returning its result.
    #
    return [uplevel 1 $command]
  }

  #
  # NOTE: This procedure is designed to extract the exit code for a child
  #       process run via [exec] using the value of $::errorCode.  It will
  #       always return either a valid integer -OR- the specified default
  #       value, which may be an empty string.
  #
  proc maybeGetExitCode { value {default ""} } {
    if {[lindex $value 0] eq "CHILDSTATUS"} then {
      set status [lindex $value 2]

      if {[string is integer -strict $status]} then {
        return $status
      }
    }

    return $default
  }

  #
  # NOTE: Provide the Eagle "execute" package to the interpreter.
  #
  package provide Eagle.Execute \
    [expr {[isEagle] ? [info engine PatchLevel] : "1.0"}]
}
