=head1 NAME

CFX5::Commands::WIN32 - WIN32 functions for spawning processes

=head1 DESCRIPTION

This package actually defines functions in the CFX5::Commands namespace.

=cut

package CFX5::Commands;

use strict;

use CFX5::Commands::Result;

use vars qw($CVSVersion);
$CVSVersion='$Id$ ';

use CFX5::Output qw(:all);
use CFX5::CurrentConfig qw(%Config);
use Carp;

use CFX5::Win32::Commands;

sub do_cmd_quiet {
  _trace "do_cmd_quiet: @_";
  $LastCmd=$_[0];
  @LastCmd=@_;
  undef $LastCmdPID;
  undef $LastCmdError;

  # make sure we are tidied up before we start
  reap_dead_children();

  if (defined $Config{CFX5_SHELL_ON_RUN_RE}
      and $_[0] =~ m!$Config{CFX5_SHELL_ON_RUN_RE}!) {
    # for debugging, we allow people to provide a RE which starts a
    # shell rather than running the exec directly.  In this case, we
    # obviously don't want to be minimised!  So we just call back to
    # do_cmd, which will DTRT here so long as the conditions in the
    # two if statements remain the same.
    return do_cmd(@_);
  }

  check_for_executable(@_)
    or return CFX5::Commands::Result->new_not_run("Executable $_[0] not found");

  my $prv;
  if (CFX5::Output::have_console()) {
    $prv=do_cmd(@_);
  } else {
    $prv=CFX5::Win32::Commands::run_minimized(@_);
  }

  $prv->set_runerr($!);

  register_child_death(0,$prv->wait_rv());

  $?=$prv->wait_rv();

  return $prv;
}

sub do_output_cmd {
  _trace "do_output_cmd: @_";
  $LastCmd=$_[0];
  @LastCmd=@_;
  undef $LastCmdPID;
  undef $LastCmdError;

  if (defined $Config{CFX5_SHELL_ON_RUN_RE}
      and $_[0] =~ m!$Config{CFX5_SHELL_ON_RUN_RE}!) {
    # for debugging, we allow people to provide a RE which starts a
    # shell rather than running the exec directly.  In this case, we
    # obviously don't want to be minimised!  So we just call back to
    # do_cmd, which will DTRT here so long as the conditions in the
    # two if statements remain the same.
    return do_cmd(@_);
  }

  check_for_executable(@_)
    or return CFX5::Commands::Result->new_not_run("Executable $_[0] not found");

  # make sure we are tidied up before we start
  reap_dead_children();

  # returns a parsed retval
  return CFX5::Win32::Commands::get_cmd_output_min(@_);
}

sub do_input_cmd_ {
  _trace "do_input_cmd: @_";
  my $input=shift;
  $LastCmd=$_[0];
  @LastCmd=@_;
  undef $LastCmdPID;
  undef $LastCmdError;

  if (defined $Config{CFX5_SHELL_ON_RUN_RE}
      and $_[0] =~ m!$Config{CFX5_SHELL_ON_RUN_RE}!) {
    # for debugging, we allow people to provide a RE which starts a
    # shell rather than running the exec directly.  In this case, we
    # obviously don't want to be minimised!  So we just call back to
    # do_cmd, which will DTRT here so long as the conditions in the
    # two if statements remain the same.
    return do_cmd(@_);
  }

  check_for_executable(@_)
    or return CFX5::Commands::Result->new_not_run("Executable $_[0] not found");

  # make sure we are tidied up before we start
  reap_dead_children();

  # returns a parsed retval
  return CFX5::Win32::Commands::get_cmd_output_($input, 0, @_);
}

=head3 escape_argument

  $arg = escape_argument($arg);
  @args = map escape_argument($_), @args;

  Process arguments for use with the Windows command shell.

  - Escape any backslashes at end of an argument to prevent the trailing double quote added (last step below) from being escaped. We *want* the command shell to interpret this quote as a metacharacter.
  - Escape double quote preceded by optional backslashes. Both are escaped.
  - Quote arguments containing embedded whitespace or quotes.

  A backslash is used for all escaping. 

=cut

sub escape_argument
{
  my $arg = shift;

  for ($arg)
  {
    # Escape backslashes at end of argument
    s/(\\+)$/$1$1/;
    # Escape double quote preceeded by optional backslashes
    s/(\\*)(\")/$1$1\\$2/g;
    # Quote arguments with embedded whitespace or quotes
    $_ = qq("$_") if m/\s|\t|\n|\v|\"/;
  }

  return $arg;
}

1;
