/**
   @file      select_poll.c
   @author    Mitch Richling <http://www.mitchr.me/>
   @Copyright Copyright 1993 by Mitch Richling.  All rights reserved.
   @brief     The UNIX select and poll functions.@EOL
   @Keywords  UNIX I/O file select timeout poll
   @Std       ISOC 
   
              This C program is intended to illustrate how one can use
              the select(2) function to determine if a particular file
              descriptor has data to read or has an error condition
              without using a read(2) system call.  This is a very
              useful technique for network programming as well.  We
              use the select because it is a bit more portable.

              Note that select on some platforms is limited to 1024
              FDs.  64-bit Solaris has a much higher limit.  MacOS X
              allows this limit to be increased via a define.

   @Tested    
              - Solaris 2.8
              - MacOS X.2
              - Linux (RH 7.3)
 */

#include <stdio.h>              /* I/O lib         ISOC  */
#include <stdlib.h>             /* Standard Lib    ISOC  */
#include <sys/types.h>          /* UNIX types      POSIX */
#include <sys/time.h>           /* UNIX time       ????  */
#include <unistd.h>             /* UNIX std stf    POSIX */
#include <errno.h>              /* error stf       POSIX */
#include <string.h>             /* Strings         ISOC  */

int main(int argc, char *argv[]);

int main(int argc, char *argv[]) {

  fd_set readFds, exceptFds;
  struct timeval theTimeOut;

  while(1) {
    /* First we must empty(zero out) the file descriptor sets. */
    FD_ZERO(&readFds);
    FD_ZERO(&exceptFds);

    /* Next we populate the file descriptors sets with the
       file descriptors we are interested in. */
    FD_SET(STDIN_FILENO, &readFds);
    FD_SET(STDIN_FILENO, &exceptFds);

    /* select will not modify the timeout argument, but it is good form to
       reset it before each call to select(2).  The zero values makes select
       act like poll. */
    theTimeOut.tv_sec = 0;
    theTimeOut.tv_usec = 0;

    /* Finally, we can call the select function!  Note that the third
       argument is NULL.  This tells select we don't care if the
       descriptor is ready to receive data (it is standard in after all). */
    if(select(1, &readFds, NULL, &exceptFds, &theTimeOut) < 0) {
      perror("ERROR: Select");
      exit(1);
    } /* end if */

    /* Check to see if data is available for read. */
    if(FD_ISSET(STDIN_FILENO, &readFds))
      printf("STDIN has data to read...\n");
    else
      printf("STDIN has NO data to read...\n");

    /* Now check to see if the file descriptor has an error. */
    if(FD_ISSET(STDIN_FILENO, &exceptFds))
      printf("STDIN has some sort of error...\n");

    /* We sleep for a second.  This is dumb, because we could have simply
       set a timeout of 1 on the select call.  We don't do that because 
       this program is demonstrateing how to use select(2) instead of poll(2) */
    sleep(1);

  } /* end while */
} /* end func main */

