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

#include <stdio.h>
#include <sys/builtin.h>        /* For <sys/fmutex.h> */
#include <sys/fmutex.h>         /* For <sys/rmutex.h> */
#include <sys/rmutex.h>
#include <emx/io.h>
#include <emx/startup.h>

/* See app/iodata.c. */

extern int _nfiles;
extern int _files[];

#if defined (__MT__)
_rmutex _streamv_rmutex;        /* See io/_newstre.c */
#endif


/* These variables must be initialized as no extended dictionary
   entries are built for COMDEF. */

FILE _streamv[_NFILES] = {{0}};

struct streamvec _streamvec_head = {_streamv, NULL, _NFILES};

#if defined (__MT__)

/* If we don't preallocate the first entry, _CRT_init() will call
   malloc() which breaks fork() because the heap object of the EXE
   file won't be used. */

static struct _file2 _streamv2[_NFILES];

struct streamvec2 _streamvec2_head = {_streamv2, NULL, _NFILES};

#endif

/* The buffer for stdin. */

static char ibuf[BUFSIZ];


/* Initialize the streams -- this function will be called by
   _startup() via the __crtinit1__ set vector. */

void _init_streams (void)
{
  int i;

#if defined (__MT__)
  _rmutex_checked_create (&_streamv_rmutex, 0);
#endif

  for (i = 0; i < _nfiles && i < _streamvec_head.n; ++i)
    {
      _streamv[i]._flags = 0;
      /* O_TEXT is set by init_files() for all valid handles. */
      if (_files[i] != 0)
        {
          _streamv[i]._flags |= _IOOPEN;
          _streamv[i]._ptr = NULL;
          _streamv[i]._buffer = NULL;
          _streamv[i]._rcount = 0;
          _streamv[i]._wcount = 0;
          _streamv[i]._handle = i;
          _streamv[i]._buf_size = 0;
          _streamv[i]._tmpidx = 0;
          _streamv[i]._pid = 0;
          _streamv[i]._flush = _flushstream;
          _streamv[i]._ungetc_count = 0;
          switch (i)
            {
            case 0:

              /* stdin is always buffered. */

              _streamv[0]._flags |= _IOREAD | _IOFBF | _IOBUFUSER;
              _streamv[0]._ptr = ibuf;
              _streamv[0]._buffer = ibuf;
              _streamv[0]._buf_size = BUFSIZ;
              break;

            case 1:

              /* stdout is buffered unless it's connected to a
                 device. */

              _streamv[i]._flags |= (_IOWRT | _IOBUFNONE
                                     | ((_files[i] & F_DEV)
                                        ? _IONBF : _IOFBF));
              break;

            case 2:

              /* stderr is always unbuffered. */

              _streamv[i]._flags |= _IOWRT | _IOBUFNONE | _IONBF;
              break;

            default:

              /* All other streams are buffered unless connected to a
                 device. */

              _streamv[i]._flags |= (_IORW | _IOBUFNONE
                                     | ((_files[i] & F_DEV)
                                        ? _IONBF : _IOFBF));
              break;
            }
          if (_setmore (&_streamv[i], 0) != 0)
            abort ();
        }
    }
}


/* Shutdown the streams -- this function will be called by _cleanup()
   via the __crtexit1__ set vector.  Do not close the streams as this
   function is called by abort() and the signal handler might want to
   print something.  (ISO 9899-1990 lets this undefined.) */

void _exit_streams (void)
{
  _flushall ();
  _rmtmp ();
}

_CRT_INIT1 (_init_streams)
_CRT_EXIT1 (_exit_streams)
