/* startup.c (emx+gcc) -- Copyright (c) 1990-1993 by Eberhard Mattes */

#include <sys/emx.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/ioctl.h>

#if defined (__MT__)

#define INCL_DOSSEMAPHORES
#define INCL_DOSEXCEPTIONS
#define INCL_DOSPROCESS
#define INCL_DOSERRORS
#include <os2emx.h>

/* This mutex semaphore protects the heap. */
static HMTX _heap_mutex;

/* Create semaphores for a multi-threaded program. */
void _startup_mt (void)
{
  ULONG rc;

  rc = DosCreateMutexSem (NULL, &_heap_mutex, 0, FALSE);
  if (rc != 0)
    DosBeep (466, 500);
}


/* Lock the heap. */

void _heap_lock (void)
{
  ULONG nesting, rc;

  DosEnterMustComplete (&nesting);
  do
    {
      rc = DosRequestMutexSem (_heap_mutex, SEM_INDEFINITE_WAIT);
    } while (rc == ERROR_SEM_OWNER_DIED);
  if (rc != 0)
    DosBeep (466, 500);
}

/* Release the heap. */

void _heap_unlock (void)
{
  ULONG nesting;

  DosReleaseMutexSem (_heap_mutex);
  DosExitMustComplete (&nesting);
}

#endif


/* The version of this libc. */
static const char _libc_version[] =
  " libc for emx 0.8h";

/* Display this warning if emx.dll or emx.exe is out of date. */
static const char _version_warning[] =
  "WARNING: emx 0.8h or later required\r\n";

/* The buffer for stdin. */
static char ibuf[BUFSIZ];

/* Initialize the C run-time library.  This function is called from
   crt0.s. */

void _startup (void)
{
  int i, j;

  /* Print a warning message on handle 2 (stderr) if emx.dll or
     emx.exe is out of date. */

  if (_emx_vcmp < 0x302e3868)   /* 0.8h */
    __write (2, _version_warning, strlen (_version_warning));

  /* Create semaphores for a mult-threaded program. */

#if defined (__MT__)
  _startup_mt ();
#endif

  /* Initialize the file handles and the streams. */

  for (i = 0; i < _nfiles; ++i)
    {
      _files[i] = 0;
      _lookahead[i] = -1;
      _streamv[i].flags = 0;

      /* Get the handle type.  If this fails, the handle is not open. */

      if (ioctl (i, FGETHTYPE, &j) >= 0)
        {
          _files[i] |= O_TEXT;
          if (HT_ISDEV (j))
            _files[i] |= F_DEV;
          if (j == HT_NPIPE)
            _files[i] |= F_NPIPE;
          _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;
          switch (i)
            {
            case 0:

              /* stdin is always buffered. */

              _files[0] |= O_RDONLY;
              _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. */

              _files[i] |= O_WRONLY;
              _streamv[i].flags |= (_IOWRT | _IOBUFNONE |
                                    (HT_ISDEV (j) ? _IONBF : _IOFBF));
              break;

            case 2:

              /* stderr is always unbuffered. */

              _files[i] |= O_WRONLY;
              _streamv[i].flags |= _IOWRT | _IOBUFNONE | _IONBF;
              break;

            default:

              /* All other handles can be read and written.  A handle
                 is buffered unless it's connected to a device. */

              _files[i] |= O_RDWR;
              _streamv[i].flags |= (_IORW | _IOBUFNONE |
                                    (HT_ISDEV (j) ? _IONBF : _IOFBF));
              break;
            }
        }
    }
}
