/* popen.c (emx+gcc) -- Copyright (c) 1992-1993 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;
  close (handle);
  dup (org_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);
  if (close (handle) == -1)
    return (NULL);
  i = dup (pipe_remote);
  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, NULL);
  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);
}
