WORD_DESC *
command_substitute (string, quoted)
     char *string;
     int quoted;
{
  pid_t pid, old_pid, old_pipeline_pgrp, old_async_pid;
  char *istring, *s;
  int result, fildes[2], function_value, pflags, rc, tflag;
  WORD_DESC *ret;

  istring = (char *)NULL;

  /* Don't fork () if there is no need to.  In the case of no command to
     run, just return NULL. */
#if 1
  for (s = string; s && *s && (shellblank (*s) || *s == '\n'); s++)
    ;
  if (s == 0 || *s == 0)
    return ((WORD_DESC *)NULL);
#else
  if (!string || !*string || (string[0] == '\n' && !string[1]))
    return ((WORD_DESC *)NULL);
#endif

  if (wordexp_only && read_but_dont_execute)
    {
      last_command_exit_value = EX_WEXPCOMSUB;
      jump_to_top_level (EXITPROG);
    }

  /* We're making the assumption here that the command substitution will
     eventually run a command from the file system.  Since we'll run
     maybe_make_export_env in this subshell before executing that command,
     the parent shell and any other shells it starts will have to remake
     the environment.  If we make it before we fork, other shells won't
     have to.  Don't bother if we have any temporary variable assignments,
     though, because the export environment will be remade after this
     command completes anyway, but do it if all the words to be expanded
     are variable assignments. */
  if (subst_assign_varlist == 0 || garglist == 0)
    maybe_make_export_env ();	/* XXX */

  /* Flags to pass to parse_and_execute() */
  pflags = (interactive && sourcelevel == 0) ? SEVAL_RESETLINE : 0;

  /* Pipe the output of executing STRING into the current shell. */
  if (pipe (fildes) < 0)
    {
      sys_error ("%s", _("cannot make pipe for command substitution"));
      goto error_exit;
    }

  old_pid = last_made_pid;
#if defined (JOB_CONTROL)
  old_pipeline_pgrp = pipeline_pgrp;
  /* Don't reset the pipeline pgrp if we're already a subshell in a pipeline. */
  if ((subshell_environment & SUBSHELL_PIPE) == 0)
    pipeline_pgrp = shell_pgrp;
  cleanup_the_pipeline ();
#endif /* JOB_CONTROL */

  old_async_pid = last_asynchronous_pid;
  pid = make_child ((char *)NULL, subshell_environment&SUBSHELL_ASYNC);
  last_asynchronous_pid = old_async_pid;

  if (pid == 0)
    {
      /* Reset the signal handlers in the child, but don't free the
	 trap strings.  Set a flag noting that we have to free the
	 trap strings if we run trap to change a signal disposition. */
      reset_signal_handlers ();
      if (ISINTERRUPT)
	{
	  kill (getpid (), SIGINT);
	  CLRINTERRUPT;		/* if we're ignoring SIGINT somehow */
	}	
      QUIT;	/* catch any interrupts we got post-fork */
      subshell_environment |= SUBSHELL_RESETTRAP;
    }

#if defined (JOB_CONTROL)
  /* XXX DO THIS ONLY IN PARENT ? XXX */
  set_sigchld_handler ();
  stop_making_children ();
  if (pid != 0)
    pipeline_pgrp = old_pipeline_pgrp;
#else
  stop_making_children ();
#endif /* JOB_CONTROL */

  if (pid < 0)
    {
      sys_error (_("cannot make child for command substitution"));
    error_exit:

      last_made_pid = old_pid;

      FREE (istring);
      close (fildes[0]);
      close (fildes[1]);
      return ((WORD_DESC *)NULL);
    }

  if (pid == 0)
    {
      /* The currently executing shell is not interactive. */
      interactive = 0;

      set_sigint_handler ();	/* XXX */

      free_pushed_string_input ();

      /* Discard  buffered stdio output before replacing the underlying file
	 descriptor. */
      fpurge (stdout);

      if (dup2 (fildes[1], 1) < 0)
	{
	  sys_error ("%s", _("command_substitute: cannot duplicate pipe as fd 1"));
	  exit (EXECUTION_FAILURE);
	}

      /* If standard output is closed in the parent shell
	 (such as after `exec >&-'), file descriptor 1 will be
	 the lowest available file descriptor, and end up in
	 fildes[0].  This can happen for stdin and stderr as well,
	 but stdout is more important -- it will cause no output
	 to be generated from this command. */
      if ((fildes[1] != fileno (stdin)) &&
	  (fildes[1] != fileno (stdout)) &&
	  (fildes[1] != fileno (stderr)))
	close (fildes[1]);

      if ((fildes[0] != fileno (stdin)) &&
	  (fildes[0] != fileno (stdout)) &&
	  (fildes[0] != fileno (stderr)))
	close (fildes[0]);

#ifdef __CYGWIN__
      /* Let stdio know the fd may have changed from text to binary mode, and
	 make sure to preserve stdout line buffering. */
      freopen (NULL, "w", stdout);
      sh_setlinebuf (stdout);
#endif /* __CYGWIN__ */

      /* This is a subshell environment. */
      subshell_environment |= SUBSHELL_COMSUB;

      /* Many shells do not appear to inherit the -v option for command
	 substitutions. */
      change_flag ('v', FLAG_OFF);

      /* When inherit_errexit option is not enabled, command substitution does
	 not inherit the -e flag.  It is enabled when Posix mode is enabled */
      if (inherit_errexit == 0)
        {
          builtin_ignoring_errexit = 0;
	  change_flag ('e', FLAG_OFF);
        }
      set_shellopts ();

      /* If we are expanding a redirection, we can dispose of any temporary
	 environment we received, since redirections are not supposed to have
	 access to the temporary environment.  We will have to see whether this
	 affects temporary environments supplied to `eval', but the temporary
	 environment gets copied to builtin_env at some point. */
      if (expanding_redir)
	{
	  flush_temporary_env ();
	  expanding_redir = 0;
	}

      remove_quoted_escapes (string);

      startup_state = 2;	/* see if we can avoid a fork */
      /* Give command substitution a place to jump back to on failure,
	 so we don't go back up to main (). */
      result = setjmp_nosigs (top_level);

      /* If we're running a command substitution inside a shell function,
	 trap `return' so we don't return from the function in the subshell
	 and go off to never-never land. */
      if (result == 0 && return_catch_flag)
	function_value = setjmp_nosigs (return_catch);
      else
	function_value = 0;

      if (result == ERREXIT)
	rc = last_command_exit_value;
      else if (result == EXITPROG)
	rc = last_command_exit_value;
      else if (result)
	rc = EXECUTION_FAILURE;
      else if (function_value)
	rc = return_catch_value;
      else
	{
	  subshell_level++;
	  rc = parse_and_execute (string, "command substitution", pflags|SEVAL_NOHIST);
	  subshell_level--;
	}

      last_command_exit_value = rc;
      rc = run_exit_trap ();
#if defined (PROCESS_SUBSTITUTION)
      unlink_fifo_list ();
#endif
      exit (rc);
    }
  else
    {
#if defined (JOB_CONTROL) && defined (PGRP_PIPE)
      close_pgrp_pipe ();
#endif /* JOB_CONTROL && PGRP_PIPE */

      close (fildes[1]);

      tflag = 0;
      istring = read_comsub (fildes[0], quoted, &tflag);

      close (fildes[0]);

      current_command_subst_pid = pid;
      last_command_exit_value = wait_for (pid);
      last_command_subst_pid = pid;
      last_made_pid = old_pid;

#if defined (JOB_CONTROL)
      /* If last_command_exit_value > 128, then the substituted command
	 was terminated by a signal.  If that signal was SIGINT, then send
	 SIGINT to ourselves.  This will break out of loops, for instance. */
      if (last_command_exit_value == (128 + SIGINT) && last_command_exit_signal == SIGINT)
	kill (getpid (), SIGINT);

      /* wait_for gives the terminal back to shell_pgrp.  If some other
	 process group should have it, give it away to that group here.
	 pipeline_pgrp is non-zero only while we are constructing a
	 pipeline, so what we are concerned about is whether or not that
	 pipeline was started in the background.  A pipeline started in
	 the background should never get the tty back here.  We duplicate
	 the conditions that wait_for tests to make sure we only give
	 the terminal back to pipeline_pgrp under the conditions that wait_for
	 gave it to shell_pgrp.  If wait_for doesn't mess with the terminal
	 pgrp, we should not either. */
      if (interactive && pipeline_pgrp != (pid_t)0 && running_in_background == 0 &&
	   (subshell_environment & (SUBSHELL_ASYNC|SUBSHELL_PIPE)) == 0)
	give_terminal_to (pipeline_pgrp, 0);
#endif /* JOB_CONTROL */

      ret = alloc_word_desc ();
      ret->word = istring;
      ret->flags = tflag;

      return ret;
    }