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

/* Regression test for readv() and writev(). */

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

#define FNAME "rwv.tmp"

static char *text[17] =
{
  "This ",
  "is ",
  "a ",
  "test ",
  "file ",
  "for ",
  "testing ",
  "the ",
  "readv",
  "()",
  " ",
  "and",
  " writev",
  "()",
  "",
  " functions",
  "\n"
};


static int create_test_file (void)
{
  int fd;

  fd = open (FNAME, O_BINARY | O_WRONLY | O_CREAT | O_TRUNC,
             S_IREAD | S_IWRITE);
  if (fd < 0)
    {
      perror ("open()");
      exit (1);
    }
  return fd;
}


static int open_test_file (void)
{
  int fd;

  fd = open (FNAME, O_BINARY | O_RDONLY);
  if (fd < 0)
    {
      perror ("open()");
      exit (1);
    }
  return fd;
}


static void test1 (int n)
{
  struct iovec iov[17];
  int len[17];
  char buf[17][20];
  char bigbuf[400];
  int fd, i, total, r;

  total = 0;
  for (i = 0; i < n; ++i)
    {
      len[i] = strlen (text[i]);
      total += len[i];
    }

  fd = create_test_file ();

  for (i = 0; i < n; ++i)
    {
      iov[i].iov_base = text[i];
      iov[i].iov_len = len[i];
    }

  errno = 0;
  r = writev (fd, iov, n);
  if (n <= 0 || n > 16)
    {
      if (r != -1)
        {
          fprintf (stderr, "writev (fd, iov, %d) returned %d instead of -1\n",
                   n, r);
          exit (1);
        }
      if (errno != EINVAL)
        {
          fprintf (stderr, "writev (fd, iov, %d) set errno to %d "
                   "instead of %d\n", n, errno, EINVAL);
          exit (1);
        }
      close (fd);
      remove (FNAME);
      return;
    }

  if (r < 0)
    {
      perror ("writev()");
      exit (1);
    }
  if (r != total)
    {
      fprintf (stderr, "writev() returned %d, expected %d\n", r, total);
      exit (1);
    }
  close (fd);

  fd = open_test_file ();
  if (fd < 0)
    {
      perror ("open()");
      exit (1);
    }
  r = read (fd, bigbuf, sizeof (bigbuf));
  if (r < 0)
    {
      perror ("read()");
      exit (1);
    }
  if (r != total)
    {
      fprintf (stderr, "read() returned %d, expected %d\n", r, total);
      exit (1);
    }
  r = 0;
  for (i = 0; i < n; ++i)
    {
      if (memcmp (bigbuf + r, text[i], len[i]) != 0)
        {
          fprintf (stderr, "writev() vs. read() mismatch\n");
          exit (1);
        }
      r += len[i];
    }

  lseek (fd, 0, SEEK_SET);

  for (i = 0; i < n; ++i)
    {
      memset (buf[i], '*', sizeof (buf[i]));
      iov[i].iov_base = buf[i];
      iov[i].iov_len = len[i];
    }

  r = readv (fd, iov, n);
  if (r < 0)
    {
      perror ("readv()");
      exit (1);
    }
  if (r != total)
    {
      fprintf (stderr, "readv() returned %d, expected %d\n", r, total);
      exit (1);
    }
  r = 0;
  for (i = 0; i < n; ++i)
    {
      if (memcmp (buf[i], text[i], len[i]) != 0)
        {
          fprintf (stderr, "writev() vs. readv() mismatch\n");
          exit (1);
        }
      if (buf[i][len[i]] != '*')
        {
          fprintf (stderr, "readv() wrote after end of buffer\n");
          exit (1);
        }
      r += len[i];
    }
  close (fd);
  remove (FNAME);
}


static void test2 (int n)
{
  struct iovec iov[16];
  int fd, i, r;

  fd = create_test_file ();

  for (i = 0; i < n; ++i)
    {
      iov[i].iov_base = text[i];
      iov[i].iov_len = strlen (text[i]);
    }
  iov[n-1].iov_len = -1;

  errno = 0;
  r = writev (fd, iov, n);
  if (r != -1)
    {
      fprintf (stderr, "test2(%d): writev() returned %d instead of -1\n",
               n, r);
      exit (1);
    }
  if (errno != EINVAL)
    {
      fprintf (stderr, "test2(%d): writev() set errno to %d instead of %d\n",
               n, errno, EINVAL);
      exit (1);
    }
  close (fd);
  remove (FNAME);
}


#if 0   /* write() does not yet check HANDLE if NBYTE is zero. */

static void test3 (void)
{
  struct iovec iov[1];
  int fd, r;

  fd = create_test_file ();
  close (fd);
  remove (FNAME);

  iov[0].iov_base = text[0];
  iov[0].iov_len = 0;

  r = writev (fd, iov, 1);
  if (r != -1)
    {
      fprintf (stderr, "test3: writev() returned %d instead of -1\n", r);
      exit (1);
    }
  if (errno != EBADF)
    {
      fprintf (stderr, "test3: writev() set errno to %d instead of %d\n",
               errno, EINVAL);
      exit (1);
    }
}

#endif


int main (void)
{
  int i;

  for (i = 0; i < 18; ++i)
    test1 (i);
  for (i = 1; i < 17; ++i)
    test2 (i);
#if 0
  test3 ();
#endif
  return 0;
}
