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

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

#define min(a,b) (((a) < (b)) ? (a) : (b))

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

  p = wait (&t);
  if (p == -1)
    perror ("wait");
  else 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;

  rc = dup2 (from, to);
  if (rc == -1)
    {
      perror ("dup2");
      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], handles[256], pids[256];
  int org_stdout;
  int i, j, k, n, pid;
  char *nargv[1024], buf[70], *p;
  fd_set rfds;
  struct timeval tv;

  if (argc < 2)
    {
      fputs ("Usage: select <program> ...\n", stderr);
      return 1;
    }
  signal (SIGCHLD, handler);
  org_stdout = dup (STDOUT_FILENO);
  if (org_stdout < 0)
    {
      perror ("dup stdout");
      return 2;
    }
  private (org_stdout);
  n = 0;
  for (i = 1; i < argc; ++i)
    {
      if (pipe (ph) != 0)
        {
          perror ("pipe");
          return 2;
        }
      private (ph[0]);
      my_dup2 (ph[1], STDOUT_FILENO);
      p = argv[i]; j = 0;
      while ((nargv[j++] = strtok (p, " \t")) != NULL)
        p = NULL;
      pid = spawnvp (P_NOWAIT, nargv[0], nargv);
      if (pid == -1)
        {
          perror ("spawnlp");
          return 2;
        }
      handles[n] = ph[0];
      pids[n] = pid;
      ++n;
      dup2 (org_stdout, STDOUT_FILENO);
    }
  do
    {
      FD_ZERO (&rfds);
      for (i = 0; i < n; ++i)
        if (handles[i] >= 0)
          FD_SET (handles[i], &rfds);
      tv.tv_sec = 10;
      tv.tv_usec = 0;
      j = select (FD_SETSIZE, &rfds, NULL, NULL, &tv);
      if (j < 0)
        {
          perror ("select");
          if (errno == EINTR)
            continue;
        }
      else
        printf ("j=%d\n", j);
      k = 0;
      if (j == 0)
        {
          for (i = 0; i < n; ++i)
            if (pids[i] >= 0)
              {
                if (kill (pids[i], 0) >= 0)
                  ++k;
                else
                  {
                    close (handles[i]);
                    pids[i] = -1;
                    handles[i] = -1;
                  }
              }
        }
      else
        for (i = 0; i < n; ++i)
          {
            ++k;
            if (handles[i] >= 0 && FD_ISSET (handles[i], &rfds) &&
                ioctl (handles[i], FIONREAD, &j) >= 0)
              {
                if (j > 0)
                  {
                    printf ("*");
                    j = read (handles[i], buf, min (j, sizeof (buf)));
                    printf ("%d: [", i);
                    fwrite (buf, 1, j, stdout);
                    printf ("]\n");
                  }
              }
          }
    } while (k != 0);
  return 0;
}
