#include <sys/time.h>
#include <sys/types.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>

int main(int argc, char **argv)
{
   int fd[2];
   int i;
   char buf[2];
   fd_set write_fds;
   struct timeval tv;
   ssize_t n;
   int status;

   /* initialize */
   buf[0] = 'h';
   buf[1] = 'i';

   do
   {
      /* create pipe */
      if (0 > pipe(fd))
      {
         printf("pipe error - %s\n", strerror(errno));
         break;
      }

      /*
       * loop four times
       * select for write, then write one byte
       * after the second write, do a read
       * odd selects succeed, even fail
       */
      for (i = 0; i < 4; i++)
      {
         printf("iteration %d\n", i + 1);

         status = 0;

         /* do select */
         FD_ZERO(&write_fds);
         FD_SET(fd[1], &write_fds);
         tv.tv_sec = 0;
         tv.tv_usec = 0;
         switch (select(fd[1] + 1, NULL, &write_fds, NULL, &tv))
         {
            case -1:
               /* should probably check for EINTR and/or EWOULDBLOCK */
               printf("select error - %s\n", strerror(errno));
               break;
            case 0:
               /* no I/O */
               puts("select returned 0 -- pipe not writable");
               break;
            default:
               /* make sure our fd is writable */
               if (FD_ISSET(fd[1], &write_fds))
               {
                  puts("select says pipe is writable");
                  status = 1;
               }
               else
                  puts("select says pipe is not writable");
               break;
         }

         /* do write */
         n = write(fd[1], buf + (i % 2), 1);
         switch (n)
         {
            case -1:
               /* should probably check for EINTR and/or EWOULDBLOCK */
               printf("write error - %s\n", strerror(errno));
               break;
            case 0:
               /* no I/O */
               puts("write returned 0 -- pipe closed");
               break;
            default:
               printf("write succeeded - %d bytes written\n", n);
               if (0 == status)
                  puts("select bug");
               break;
         }

         /* do read */
         if (0 == ((i + 1) % 2))
         {
            n = read(fd[0], buf, sizeof(buf));
            switch (n)
            {
               case -1:
                  /* should probably check for EINTR and/or EWOULDBLOCK */
                  printf("write error - %s\n", strerror(errno));
                  break;
               case 0:
                  /* no I/O */
                  puts("read returned 0 -- pipe closed");
                  break;
               default:
                  printf("read succeeded - %d bytes read\n", n);
                  break;
            }
         }
      }
   }
   while (0);

   exit(0);
}
