/* write1.c */

/* Test write()'s behavior on (full) text-mode pipes. */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <io.h>
#include <errno.h>
#include <getopt.h>
#include <emx/io.h>

extern int _pipe_size;

static void usage (void)
{
  fprintf (stderr,
           "Usage: write1 [-c<count>] [-p<pipe_size>] [-w<length>] [-r<length>]\n");
  exit (1);
}


int main (int argc, char *argv[])
{
  int fd[2];
  int c, n, i, j, ri, wi;
  int count, ps, w_len, r_len, b_len;
  int we, wp, wf, re, rp, rf, ce, lfp;
  char buf[512];
  char w_msg[] = "a\nbc\ndef\nghij\n\r\nk\n\n";
  char r_msg[] = "a\r\nbc\r\ndef\r\nghij\r\n\r\r\nk\r\n\r\n";

  count = 10000; ps = 31; w_len = strlen (w_msg); b_len = 4;

  while ((c = getopt (argc, argv, "c:p:r:w:")) != -1)
    {
      switch (c)
        {
        case 'c':
          count = atoi (optarg);
          if (count < 1)
            usage ();
          break;
        case 'p':
          ps = atoi (optarg);
          if (ps < 0)
            usage ();
          break;
        case 'r':
          b_len = atoi (optarg);
          if (b_len < 1 || b_len > sizeof (buf))
            usage ();
          break;
        case 'w':
          w_len = atoi (optarg);
          if (w_len < 1 || w_len > strlen (w_msg))
            usage ();
          break;
        default:
          usage ();
        }
    }

  if (optind != argc)
    usage ();

  _pipe_size = ps;

  if (pipe (fd) != 0)
    {
      perror ("pipe");
      return 2;
    }
  if (fcntl (fd[0], F_SETFL, O_NONBLOCK) != 0)
    {
      perror ("fcntl"); return 2;
    }
  if (fcntl (fd[1], F_SETFL, O_NONBLOCK) != 0)
    {
      perror ("fcntl"); return 2;
    }
  if (setmode (fd[0], O_BINARY) == -1)
    {
      perror ("setmode"); return 2;
    }
  if (setmode (fd[1], O_TEXT) == -1)
    {
      perror ("setmode"); return 2;
    }
  r_len = 0;
  for (i = 0; i < w_len; ++i)
    r_len += (w_msg[i] == '\n' ? 2 : 1);
  ri = wi = 0;
  we = wp = wf = 0;
  re = rp = rf = 0;
  ce = lfp = 0;
  for (; count > 0; --count)
    {
      int *pflags = _fd_flags (fd[1]);
      if (pflags == NULL) abort ();
      if (*pflags & F_WRCRPEND)
        ++lfp;
      i = w_len - wi;
      n = write (fd[1], w_msg + wi, i);
      if (n == -1)
        {
          if (errno != EAGAIN)
            {
              perror ("write");
              return 2;
            }
          ++we;
        }
      else
        {
          if (n == i)
            {
              ++wf; wi = 0;
            }
          else
            {
              ++wp; wi += n;
            }
        }

      i = r_len - ri;
      if (i > b_len)
        i = b_len;
      n = read (fd[0], buf, i);
      if (n == -1)
        {
          if (errno != EAGAIN)
            {
              perror ("read");
              return 2;
            }
          ++re;
        }
      else
        {
          if (memcmp (buf, r_msg + ri, n) != 0)
            {
              ++ce;
              for (j = 0; j <= r_len - n; ++j)
                if (memcmp (buf, r_msg + j, n) == 0)
                  {
                    ri = j; break;
                  }
            }
          if (n == i)
            ++rf;
          else
            ++rp;
          ri += n;
          if (ri == r_len)
            ri = 0;
        }
    }
  printf ("read:       EAGAIN: %4d, partial: %4d, full: %d\n", re, rp, rf);
  printf ("write:      EAGAIN: %4d, partial: %4d, full: %d\n", we, wp, wf);
  printf ("mismatches: %d%s\n", ce, (ce == 0 ? "" : " <-- ERROR"));
  printf ("F_WRCRPEND: %d\n", lfp);
  return ce != 0 ? 1 : 0;
}
