/* opentest.c (emx+gcc) */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <io.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>

#define FNAME "open.dat"

#if defined (__IBMCPP__)
#define open _open
#define read _read
#define write _write
#define filelength _filelength
#endif

static int fd = -1;

static int open_test (int mode)
{
  if (fd != -1)
    close (fd);
  fd = open (FNAME, mode, S_IREAD | S_IWRITE);
  return (fd == -1 ? -1 : 0);
}


static void open_fail (int mode, int e)
{
  if (open_test (mode) == 0)
    {
      fprintf (stderr,
               "open (" FNAME ", 0x%x) succeeded, but should have failed\n",
               mode);
      exit (1);
    }
  if (e != errno)
    {
      fprintf (stderr,
               "open (" FNAME ", 0x%x): errno is %d, should be %d\n",
               mode, errno, e);
      exit (1);
    }
}


static void open_ok (int mode)
{
  if (open_test (mode) != 0)
    {
      fprintf (stderr, "open (" FNAME ", 0x%x) failed\n", mode);
      exit (1);
    }
}


static void add (int n)
{
  char buf[512];
  int i;

  memset (buf, '*', sizeof (buf));
  while (n > 0)
    {
      i = n;
      if (sizeof (buf) < i)
        i = sizeof (buf);
      i = write (fd, buf, i);
      if (i == -1)
        {
          fprintf (stderr, "write() failed\n");
          exit (1);
        }
      n -= i;
    }
}


static void rw (int rok, int wok)
{
  char buf[1];

  if (read (fd, buf, 1) != rok)
    {
      fprintf (stderr, "rw() failed: read\n");
      exit (1);
    }
  buf[0] = '#';
  if (write (fd, buf, 1) != wok)
    {
      fprintf (stderr, "rw() failed: write\n");
      exit (1);
    }
}



static void size (long n)
{
  long is;

  is = filelength (fd);
  if (is != n)
    {
      fprintf (stderr, "Wrong file size %ld, should be %ld\n", is, n);
      exit (1);
    }
}


static void del (void)
{
  if (fd != -1)
    {
      close (fd);
      fd = -1;
    }
  remove (FNAME);
}


int main (void)
{
  atexit (del);
  del ();

  open_fail (O_RDONLY, ENOENT);
  open_fail (O_WRONLY, ENOENT);
  open_fail (O_RDWR, ENOENT);

  open_fail (O_RDONLY | O_TRUNC, EINVAL);
  open_fail (O_WRONLY | O_TRUNC, ENOENT);
  open_fail (O_RDWR | O_TRUNC, ENOENT);

  open_ok (O_CREAT | O_WRONLY); del ();
  open_fail (O_CREAT | O_RDONLY, EINVAL);
  open_ok (O_CREAT | O_RDWR); del ();

  open_ok (O_CREAT | O_WRONLY | O_EXCL); del ();
  open_fail (O_CREAT | O_RDONLY | O_EXCL, EINVAL);
  open_ok (O_CREAT | O_RDWR   | O_EXCL);

  open_fail (O_CREAT | O_WRONLY | O_EXCL, EEXIST);
  open_fail (O_CREAT | O_RDONLY | O_EXCL, EINVAL);
  open_fail (O_CREAT | O_RDWR   | O_EXCL, EEXIST);

  /* O_EXCL is ignored unless O_CREAT is given. */

  open_ok (O_RDONLY | O_EXCL);
  open_ok (O_RDWR | O_EXCL);

  open_ok (O_WRONLY | O_CREAT | O_TRUNC); add (1);
  open_ok (O_RDONLY); rw (1, -1);
  open_ok (O_WRONLY | O_CREAT | O_TRUNC); add (1);
  open_ok (O_WRONLY); rw (-1, 1);
  open_ok (O_WRONLY | O_CREAT | O_TRUNC); add (1);
  open_ok (O_RDWR); rw (1, 1);

  del ();
  open_ok (O_RDWR | O_CREAT | O_TRUNC);
  size (0);
  add (1);
  size (1);
  open_ok (O_RDWR | O_CREAT);
  size (1);
  open_ok (O_RDWR | O_CREAT | O_TRUNC);
  size (0);

  return (0);
}
