/* fdopen.c (emx+gcc) -- Copyright (c) 1990-1996 by Eberhard Mattes */

#include <stdio.h>
#include <io.h>
#include <fcntl.h>
#include <errno.h>
#include <emx/io.h>

#define FALSE   0
#define TRUE    1

/* Bug: doesn't check for compatible modes (O_ACCMODE) */

FILE *_fdopen (int handle, const char *mode)
{
  char ok, bt;
  FILE *dst;
  int omode;

  if (_fd_flags (handle) == NULL)
    {
      errno = EBADF;
      return NULL;
    }
  dst = _newstream ();
  switch (*mode)
    {
    case 'r':
      dst->_flags = _IOREAD;
      break;
    case 'w':
      dst->_flags = _IOWRT;
      break;
    case 'a':
      dst->_flags = _IOWRT;
      break;
    default:
      _closestream (dst);
      return NULL;
    }
  ++mode; ok = TRUE; bt = FALSE; omode = 0;
  while (*mode != 0 && ok)
    {
      switch (*mode)
        {
        case 't':
          if (bt)
            ok = FALSE;
          else
            {
              bt = TRUE;
              omode = O_TEXT;
            }
          break;
        case 'b':
          if (bt)
            ok = FALSE;
          else
            {
              bt = TRUE;
              omode = O_BINARY;
            }
          break;
        case '+':
          if (dst->_flags & _IORW)
            ok = FALSE;
          else
            {
              dst->_flags &= ~(_IOREAD|_IOWRT);
              dst->_flags |= _IORW;
            }
          break;
        default:
          ok = FALSE; break;
        }
      if (ok) ++mode;
    }
  if (bt)
    _setmode (handle, omode);
  dst->_handle = handle;
  dst->_ptr = NULL;
  dst->_buffer = NULL;
  dst->_buf_size = 0;
  dst->_rcount = 0;
  dst->_wcount = 0;
  dst->_flags |= _IOOPEN | _IOBUFNONE;
  dst->_flush = _flushstream;
  dst->_ungetc_count = 0;
  if (_setmore (dst, 1) != 0)
    return NULL;
  return dst;
}
