/* emx/io.h (emx+gcc) */

#ifndef _EMX_IO_H
#define _EMX_IO_H

#if defined (__cplusplus)
extern "C" {
#endif

#if !defined (NULL)
#if defined (__cplusplus)
#define NULL 0
#else
#define NULL ((void *)0)
#endif
#endif

#if !defined (_SIZE_T)
#define _SIZE_T
typedef unsigned long size_t;
#endif

/* Low-level i/o */

/*      O_ACCMODE   0x00000003 */
/*      O_NDELAY    0x00000004 */
/*      O_APPEND    0x00000008 */
/*      O_TEXT      0x00000010 */
#define F_EOF       0x00000020
#define F_TERMIO    0x00000040
#define F_DEV       0x00000080
/*      O_BINARY    0x00000100 */
/*      O_CREAT     0x00000200 */
/*      O_TRUNC     0x00000400 */
/*      O_EXCL      0x00000800 */
/*      O_NOINHERIT 0x00001000 */
/*      O_SYNC      0x00002000 */
/*      O_NOCTTY    0x00004000 */
/*      O_SIZE      0x00008000 */
#define F_SOCKET    0x10000000
#define F_PIPE      0x20000000
#define F_WRCRPEND  0x40000000
#define F_CRLF      0x80000000

/* stdio */

/*      _IOREAD     0x00000001 */
/*      _IOWRT      0x00000002 */
/*      _IORW       0x00000004 */
/*      _IOEOF      0x00000008 */
/*      _IOERR      0x00000010 */
/*      _IOLBF      0x00000020 */
/*      _IONBF      0x00000040 */

/* This bit is set if the stream is open. */

#define _IOOPEN     0x00000080

/* Mask for the buffer type. */

#define _IOBUFMASK  0x00000700

/* This buffer type is set until a buffer has been assigned. */

#define _IOBUFNONE  0x00000000

/* This buffer type is set by setvbuf() if a user-allocated buffer is
   used. */

#define _IOBUFUSER  0x00000100

/* This buffer type is set by _fbuf() if a single-character buffer is
   used. */

#define _IOBUFCHAR  0x00000200

/* This buffer type is set by _fbuf() if the stream buffer has been
   allocated by the library, with malloc().  The buffer will be
   deallocated by fclose(). */

#define _IOBUFLIB   0x00000300

/* This buffer type is set by _tmpbuf1() to indicate that a temporary
   buffer has been assigned to the stream. */

#define _IOBUFTMP   0x00000400

/* This bit is set by tmpfile() to indicate a temporary file, to be
   deleted by fclose(). */

#define _IOTMP      0x00000800

/* This bit is set for special streams which don't have an underlying
   file. */

#define _IOSPECIAL  0x00001000

/* This bit is set by ungetc() to indicate that pushed-back characters
   have been stored to the stream buffer -- fseek() must cause the
   buffer to be reread. */

#define _IOUNGETC   0x00002000

/* This bit is set by _newstream() to avoid reusing the same slot in
   another thread. */

#define _IONEW      0x00004000

/* This bit is set for byte-oriented streams. */

#define _IOBYTE     0x00008000

/* This bit is set for wide-oriented streams. */

#define _IOWIDE     0x00010000


#define _FLUSH_FLUSH  (-1)
#define _FLUSH_FILL   (-2)

struct _FILE;

struct _file2
{
  struct _FILE *owner;
#if defined (_SYS_RMUTEX_H)
  _rmutex rsem;
#else
  char rsem_ersatz[16];
#endif
};

#define nbuf(s) (((s)->_flags & _IOBUFMASK) == _IOBUFNONE)
#define cbuf(s) (((s)->_flags & _IOBUFMASK) == _IOBUFCHAR)
#define ubuf(s) (((s)->_flags & _IOBUFMASK) == _IOBUFUSER)
#define lbuf(s) (((s)->_flags & _IOBUFMASK) == _IOBUFLIB)
#define tbuf(s) (((s)->_flags & _IOBUFMASK) == _IOBUFTMP)

#define bbuf(s) (ubuf (s) || lbuf (s) || tbuf (s))

#define _tmpbuf(s,b) (nbuf (s) || cbuf (s) \
                      ? b = alloca (BUFSIZ), _tmpbuf1 (s, b) : 0)
#define _endbuf(s) (tbuf (s) ? _endbuf1 (s) : 0)

#define alloca(x) __builtin_alloca(x)

struct streamvec
{
  struct _FILE *vec;
  struct streamvec *next;
  int n;
};

struct fdvec
{
  int *flags;
  int *lookahead;
  struct fdvec *next;
  int n;
};

extern struct streamvec _streamvec_head;

extern int _io_ninherit;
extern struct fdvec _fdvec_head;

#if defined (__MT__)

/* This is currently used only in the multi-thread libraries.  We
   can't use and reallocate a single array because rmutex semaphores
   cannot be moved. */

struct streamvec2
{
  struct _file2 *vec;
  struct streamvec2 *next;
  int n;
};

extern struct streamvec2 _streamvec2_head;

#if defined (_SYS_RMUTEX_H)

/* This semaphore (defined in app/stdio.c) protects _streamv[].  Only
   concurrent access by _newstream(), _setmore(), and freopen() in
   different threads must be prevented to avoid using one element of
   _streamv[] for multiple streams (in different threads).  All other
   functions may concurrently access _streamv[], even concurrently to
   _newstream(), _setmore(), and freopen(). */

extern _rmutex _streamv_rmutex;

#define STREAMV_LOCK    _rmutex_checked_request (&_streamv_rmutex, _FMR_IGNINT)
#define STREAMV_UNLOCK  _rmutex_checked_release (&_streamv_rmutex)

#define STREAM_LOCK(f) \
  (_rmutex_request (&(f)->_more->rsem, _FMR_IGNINT) != 0 \
   ? abort () : (void)0)

#define STREAM_UNLOCK(f) \
  (_rmutex_release (&(f)->_more->rsem) != 0 ? abort () : (void)0)

#define STREAM_LOCK_NOWAIT(f) \
  (_rmutex_request (&(f)->_more->rsem, _FMR_NOWAIT) == 0)

#define STREAM_UNLOCKED(f) _rmutex_available (&(f)->_more->rsem)

#endif /* defined (_SYS_RMUTEX_H) */

#else /* !defined (__MT__) */

#define STREAMV_LOCK            (void)0
#define STREAMV_UNLOCK          (void)0

#define STREAM_LOCK(f)          (void)0
#define STREAM_UNLOCK(f)        (void)0
#define STREAM_LOCK_NOWAIT(f)   1
#define STREAM_UNLOCKED(f)      1

#endif /* !defined (__MT__) */


int _endbuf1 (struct _FILE *);
void _fbuf (struct _FILE *);
int *_fd_flags (int);
int *_fd_init (int);
int *_fd_lookahead (int);
struct _FILE *_fopen (struct _FILE *, __const__ char *, __const__ char *,
    int, int);
int _flushstream (struct _FILE *, int);
void _closestream (struct _FILE *);
int _fflush_nolock (struct _FILE *);
int _fseek_nolock (struct _FILE *, long, int);
long _ftell_nolock (struct _FILE *);
size_t _fwrite_nolock (const void *, size_t, size_t, struct _FILE *);
int _input (struct _FILE *, __const__ char *, char *);
struct _FILE *_newstream (void);
int _output (struct _FILE *, __const__ char *, char *);
void _setdummymore (struct _FILE *, struct _file2 *);
int _setmore (struct _FILE *, int);
int _stream_read (int, void *, size_t);
int _stream_write (int, __const__ void *, size_t);
int _tmpbuf1 (struct _FILE *, void *);
int _trslash (__const__ char *, size_t, int);
int _ungetc_nolock (int, struct _FILE *);
int _vsopen (__const__ char *, int, int, char *);


#if defined (__cplusplus)
}
#endif

#endif /* not _EMX_IO_H */
