/* sys/open.c (emx+gcc) -- Copyright (c) 1992-1996 by Eberhard Mattes */

#define INCL_DOSERRORS
#include <os2emx.h>
#include <string.h>
#include <errno.h>
#include <emx/syscalls.h>
#include "syscalls.h"

int __open (const char *name, int flags, unsigned long size)
{
  ULONG rc;
  ULONG open_mode, attr, action, open_flag;
  HFILE handle;
  int fail_errno;

  /* Interpret "/dev/null" as the name of the null device "NUL".
     Interpret "/dev/tty" as the name of the console device "CON". */

  if (strcmp (name, "/dev/null") == 0)
    name = "nul";
  else if (strcmp (name, "/dev/tty") == 0)
    name = "con";

  /* Extract the access mode and sharing mode bits. */

  open_mode = flags & 0x77;

  /* Handle O_NOINHERIT and O_SYNC. */

  if (flags & _SO_NOINHERIT)
    open_mode |= OPEN_FLAGS_NOINHERIT;
  if (flags & _SO_SYNC)
    open_mode |= OPEN_FLAGS_WRITE_THROUGH;

  /* Extract the file attribute bits. */

  attr = (flags >> 8) & 0xff;
  if (_sys_umask & 0200)
    attr |= 1;

  /* Translate ERROR_OPEN_FAILED to ENOENT unless O_EXCL is set (see
     below). */

  fail_errno = ENOENT;

  /* Compute `open_flag' depending on `flags'.  Note that _SO_CREAT is
     set for O_CREAT. */

  if (flags & _SO_CREAT)
    {
      if (flags & _SO_EXCL)
        {
          open_flag = OPEN_ACTION_FAIL_IF_EXISTS | OPEN_ACTION_CREATE_IF_NEW;
          fail_errno = EEXIST;
        }
      else if (flags & _SO_TRUNC)
        open_flag = OPEN_ACTION_REPLACE_IF_EXISTS | OPEN_ACTION_CREATE_IF_NEW;
      else
        open_flag = OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_CREATE_IF_NEW;
    }
  else if (flags & _SO_TRUNC)
    open_flag = OPEN_ACTION_REPLACE_IF_EXISTS | OPEN_ACTION_FAIL_IF_NEW;
  else
    open_flag = OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_FAIL_IF_NEW;

  if (!(flags & _SO_SIZE))
    size = 0;

  /* Try to open the file and handle errors. */

  rc = DosOpen (name, &handle, &action, size, attr, open_flag, open_mode,
                NULL);
  if (rc == ERROR_OPEN_FAILED)
    {
      errno = fail_errno;
      return -1;
    }
  if (rc != 0)
    {
      _sys_set_errno (rc);
      return -1;
    }
  return handle;
}
