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

#include <stdlib.h>
#include <string.h>
#include <process.h>
#include <errno.h>
#include <emx/startup.h>
#include <emx/syscalls.h>

int _spawnve (int mode, const char *name, char * const argv[],
              char * const envp[])
{
  struct _new_proc np;
  int i, size, n;
  const char * const *p;
  char *d;
  char exe[512];

  /* Kludge alert: Unfortunately, the `mode' member was made only 16
     bits wide originally.  Bit 15 is used to indicate that the
     `mode2' member is used, which holds the upper 16 bits of MODE.
     This allows using emx 0.8 applications with emx 0.9 as emx
     doesn't look at `mode2' unless bit 15 of `mode' is set.  Of
     course, this fails if an (old) application program sets bit 15 of
     MODE. */

  np.mode = (unsigned short)(mode | 0x8000);
  np.mode2 = (unsigned short)((unsigned)mode >> 16);

  if (envp == NULL) envp = _environ;
  if (strlen (name) >= sizeof (exe) - 4)
    {
      errno = ENAMETOOLONG;
      return -1;
    }
  strcpy (exe, name);
  _defext (exe, "exe");
  np.fname_off = (unsigned long)exe;
  size = 1; n = 0;
  for (p = (const char * const *)envp; *p != NULL; ++p)
    {
      ++n; size += 1 + strlen (*p);
    }
  d = alloca (size);
  np.env_count = n; np.env_size = size;
  np.env_off = (unsigned long)d;
  for (p = (const char * const *)envp; *p != NULL; ++p)
    {
      i = strlen (*p);
      memcpy (d, *p, i+1);
      d += i+1;
    }
  *d = 0;
  size = 0; n = 0;
  for (p = (const char * const *)argv; *p != NULL; ++p)
    {
      ++n; size += 2 + strlen (*p);
    }
  d = alloca (size);
  np.arg_count = n; np.arg_size = size;
  np.arg_off = (unsigned long)d;
  for (p = (const char * const *)argv; *p != NULL; ++p)
    {
      i = strlen (*p);
      *d++ = _ARG_NONZERO;
      memcpy (d, *p, i+1);
      d += i+1;
    }
  i = __spawnve (&np);
  return i;
}
