/* pipe.c (emx+gcc) */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <io.h>
#include <process.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/wait.h>

static int alive;

static void do_wait (void)
{
  int p, t;

  p = wait (&t);
  if (p == -1)
    perror ("wait");
  else
    {
      --alive;
      if (WIFEXITED (t))
        fprintf (stderr, "Process %d terminated normally, rc=%d\n",
                 p, WEXITSTATUS (t));
      else if (WIFSTOPPED (t))
        fprintf (stderr, "Process %d stopped by signal %d\n",
                 p, WSTOPSIG (t));
      else
        fprintf (stderr, "Process %d terminated by signal %d\n",
                 p, WTERMSIG (t));
    }
}


static void handler (int sig)
{
  fprintf (stderr, "SIGCHLD: "); fflush (stderr);
  do_wait ();
  fflush (stderr);
  signal (SIGCHLD, SIG_ACK);
}


static void my_dup2 (int from, int to)
{
  int rc;

  close (to);
  rc = dup (from);
  if (rc == -1)
    {
      perror ("dup");
      exit (2);
    }
  if (rc != to)
    {
      fputs ("dup failed\n", stderr);
      exit (2);
    }
  close (from);
  if (fcntl (to, F_SETFD, 0) != 0)
    {
      perror ("fcntl");
      exit (2);
    }
}


static void private (int handle)
{
  if (fcntl (handle, F_SETFD, 1) != 0)
    {
      perror ("fcntl");
      exit (2);
    }
}


int main (int argc, char *argv[])
{
  int ph[2];
  int org_stdin, org_stdout, next_stdin, next_stdout;
  int i, j, verbose, sig;
  char *nargv[1024], *p;

  i = 1; verbose = 0; sig = 0; alive = 0;
  while (i < argc)
    if (strcmp (argv[i], "-s") == 0)
      {
        sig = 1;
        ++i;
      }
    else if (strcmp (argv[i], "-v") == 0)
      {
        verbose = 1;
        ++i;
      }
    else
      break;
  if (i >= argc)
    {
      fputs ("Usage: pipe [-s] [-v] <program1> <program2> ...\n", stderr);
      return 1;
    }
  if (sig)
    signal (SIGCHLD, handler);
  org_stdin = dup (STDIN_FILENO);
  if (org_stdin < 0)
    {
      perror ("dup stdin");
      return 2;
    }
  org_stdout = dup (STDOUT_FILENO);
  if (org_stdout < 0)
    {
      perror ("dup stdout");
      return 2;
    }
  private (STDIN_FILENO);
  private (STDOUT_FILENO);
  ph[0] = org_stdin;
  while (i < argc)
    {
      next_stdin = ph[0];
      if (i < argc-1)
        {
          if (pipe (ph) != 0)
            {
              perror ("pipe");
              return 2;
            }
          private (ph[0]);
          private (ph[1]);
          next_stdout = ph[1];
        }
      else
        next_stdout = org_stdout;
      my_dup2 (next_stdin,  STDIN_FILENO);
      my_dup2 (next_stdout, STDOUT_FILENO);
      p = argv[i]; j = 0;
      while ((nargv[j++] = strtok (p, " \t")) != NULL)
        p = NULL;
      if (spawnvp (P_NOWAIT, nargv[0], nargv) == -1)
        {
          perror ("spawnvp");
          return 2;
        }
      ++i; ++alive;
    }
  while (alive > 0)
    if (sig)
      sleep (10);
    else if (verbose)
      do_wait ();
    else if (wait (NULL) < 0)
      perror ("wait");
    else
      --alive;
  return 0;
}
