/* popen.c (emx+gcc) -- Copyright (c) 1992-1996 by Eberhard Mattes */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <process.h>
#include <unistd.h>
#include <io.h>
#include <fcntl.h>
#include <errno.h>

static void restore (int org_handle, int org_private, int handle)
{
  int saved_errno;

  saved_errno = errno;
  _dup2 (org_handle, handle);
  _close (org_handle);
  _fcntl (handle, F_SETFD, org_private);
  errno = saved_errno;
}

static FILE *make_pipe (int pipe_local, int pipe_remote, int handle,
                        const char *command, const char *mode)
{
  int i, org_handle, org_private;
  FILE *f;
  const char *sh, *base, *opt;

  _fcntl (pipe_local, F_SETFD, 1);
  org_private = _fcntl (handle, F_GETFD, 0);
  if (org_private == -1)
    return NULL;
  org_handle = _dup (handle);
  if (org_handle == -1)
    return NULL;
  _fcntl (org_handle, F_SETFD, 1);
  i = _dup2 (pipe_remote, handle);
  if (i != handle)
    {
      restore (org_handle, org_private, handle);
      errno = EBADF;
      return NULL;
    }
  if (_close (pipe_remote) == -1)
    {
      restore (org_handle, org_private, handle);
      return NULL;
    }
  f = _fdopen (pipe_local, mode);
  if (f == NULL)
    {
      restore (org_handle, org_private, handle);
      return NULL;
    }
  sh = getenv ("EMXSHELL");
  if (sh == NULL)
    sh = getenv ("COMSPEC");
  if (sh == NULL)
    {
      fclose (f);
      restore (org_handle, org_private, handle);
      errno = ENOENT;
      return NULL;
    }
  base = _getname (sh);
  if (_stricmp (base, "cmd.exe") == 0 || _stricmp (base, "4os2.exe") == 0)
    opt = "/c";
  else
    opt = "-c";
  i = _spawnlp (P_NOWAIT, sh, sh, opt, command, (char *)0);
  if (i == -1)
    {
      fclose (f);
      f = NULL;
    }
  else
    f->_pid = i;
  restore (org_handle, org_private, handle);
  return f;
}


FILE *_popen (const char *command, const char *mode)
{
  int ph[2];
  FILE *stream;
  int saved_errno;

  if (mode[0] != 'r' && mode[0] != 'w')
    {
      errno = EINVAL;
      return NULL;
    }
  if (_pipe (ph) == -1)
    return NULL;
  if (_fcntl (ph[0], F_SETFD, 1) == -1)
    return NULL;
  if (_fcntl (ph[1], F_SETFD, 1) == -1)
    return NULL;
  if (mode[0] == 'r')
    stream = make_pipe (ph[0], ph[1], STDOUT_FILENO, command, mode);
  else
    stream = make_pipe (ph[1], ph[0], STDIN_FILENO, command, mode);
  if (stream == NULL)
    {
      saved_errno = errno;
      _close (ph[0]);
      _close (ph[1]);
      errno = saved_errno;
    }
  return stream;
}
