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

#include <stdlib.h>
#include <memory.h>
#include <io.h>
#include <sys/types.h>
#include <sys/time.h>
#include <emx/io.h>
#include <emx/syscalls.h>

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

int _select (int nfds, fd_set *readfds, fd_set *writefds,
             fd_set *exceptfds, struct timeval *timeout)
{
  struct _select args;

  args.nfds = nfds;
  args.readfds = readfds;
  args.writefds = writefds;
  args.exceptfds = exceptfds;
  args.timeout = timeout;
  if (readfds != NULL)
    {
      fd_set *tmp;
      struct timeval tv;
      int i, j, k, n, nb, nw, rc;
      struct fdvec *pv;

      nw = (nfds + 31) / 32;
      if (nw < 256 / 32)
        nw = 256 / 32;
      nb = nw * 4;
      tmp = alloca (nb);
      memset (tmp, 0, nb);
      j = 0; n = 0; pv = &_fdvec_head;
      while (n < nfds && pv != NULL)
        {
          k = nfds - n;
          if (pv->n < k) k = pv->n;
          for (i = 0; i < k; ++i, ++n)
            if (pv->lookahead[i] >= 0 && FD_ISSET (n, readfds))
              {
                FD_SET (n, tmp); /* handles ready due to look ahead */
                ++j;
              }
          pv = pv->next;
        }
      if (j != 0)                /* there are handles with active look ahead */
        {
          tv.tv_sec = 0; tv.tv_usec = 0;      /* immediately return */
          args.timeout = &tv;
          rc = __select (&args);
          if (rc == 0)          /* no handles ready -> use look ahead */
            {
              memcpy (readfds, tmp, nb);
              rc = j;
            }
          else if (rc > 0)      /* merge */
            for (i = 0; i < n; ++i)
              if (FD_ISSET (i, tmp) && !FD_ISSET (i, readfds))
                {
                  FD_SET (i, readfds);
                  if (!((writefds != NULL && FD_ISSET (i, writefds))
                        || (exceptfds != NULL && FD_ISSET (i, exceptfds))))
                    ++rc;
                }
          return rc;
        }
    }
  return __select (&args);
}
