/* Derived from fork-child.c by Eberhard Mattes -- Jun 1993 */
/* Spawn an emx child process, and set up to debug it, for GDB.
   Copyright 1990, 1991, 1992 Free Software Foundation, Inc.
   Contributed by Cygnus Support.

This file is part of GDB.

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */

#include "defs.h"
#include "frame.h"  /* required by inferior.h */
#include "inferior.h"
#include "target.h"
#include "gdbcore.h"
#include "terminal.h"		/* For #ifdef TIOCGPGRP and new_tty */

#include <signal.h>

#include <process.h>
#include <fcntl.h>

#define NHANDLES 64

extern int close_sessions;

/* Start an inferior emx child process and sets inferior_pid to its pid.
   EXEC_FILE is the file to run.
   ALLARGS is a string containing the arguments to the program.
   ENV is the environment vector to pass.  Errors reported with error().  */

void
fork_inferior (exec_file, allargs, env, traceme_fun, init_trace_fun)
     char *exec_file;
     char *allargs;
     char **env;
     void (*traceme_fun) PARAMS ((void));
     void (*init_trace_fun) PARAMS ((int));
{
  int pid, nargc, a, i, handle, mode;
  char *handle_name[NHANDLES];
  int handle_saved[NHANDLES];
  int handle_child[NHANDLES];
  int handle_mode[NHANDLES];
  char *copy, *p, *q, *r;
  char **nargv;

  close_exec_file ();
  copy = concat (exec_file, " ", allargs, NULL);
  for (i = 0; i < NHANDLES; ++i)
    handle_name[i] = NULL;
  handle_name[0] = "con"; handle_mode[0] = O_RDONLY;
  handle_name[1] = "con"; handle_mode[1] = O_WRONLY;
  handle_name[2] = "con"; handle_mode[2] = O_WRONLY;
  nargc = 0; a = 0; nargv = NULL; p = copy;
  do
    {
      q = strtok (p, " \t"); p = NULL;
      if (nargc >= a)
        {
          a += 10;
          nargv = (char **)xrealloc (nargv, a * sizeof (nargv[0]));
        }
      r = NULL;
      if (q != NULL)
        {
          r = q;
          handle = -1;
          if (*r >= '0' && *r <= '9')
            {
              handle = *r - '0';
              ++r;
            }
          switch (*r)
            {
            case '<':
              ++r;
              if (handle == -1)
                handle = 0;
              mode = O_RDONLY|O_TEXT;
              break;
            case '>':
              ++r;
              if (handle == -1)
                handle = 1;
              mode = O_RDWR | O_TEXT | O_CREAT | O_TRUNC;
              if (*r == '>')
                {
                  ++r;
                  mode = O_RDWR | O_TEXT | O_CREAT | O_APPEND;
                }
              break;
            default:
              r = NULL;
              break;
            }
        }
      if (r != NULL && *r != 0 && handle < NHANDLES)
        {
          handle_name[handle] = r;
          handle_mode[handle] = mode;
        }
      else
        nargv[nargc++] = q;
    } while (q != NULL);

  for (i = 0; i < NHANDLES; ++i)
    if (handle_name[i] != NULL)
      handle_saved[i] = dup (i);
  for (i = 0; i < NHANDLES; ++i)
    if (handle_name[i] != NULL)
      {
        handle = open (handle_name[i], handle_mode[i], 0600);
        if (handle < 0)
          perror_with_name (handle_name[i]);
        handle_child[i] = handle;
        if (handle_mode[i] & O_APPEND)
          lseek (handle, 0L, SEEK_END);
      }
  for (i = 0; i < NHANDLES; ++i)
    if (handle_name[i] != NULL)
      {
        dup2 (handle_child[i], i);
        close (handle_child[i]);
      }
  for (i = 0; i < NHANDLES; ++i)
    if (handle_name[i] == NULL)
      fcntl (i, F_SETFD, 1);
  
  pid = spawnve (P_DEBUG | (close_sessions ? 0 : P_NOCLOSE),
                 exec_file, (const char * const *)nargv,
                 (const char * const *)env);

  for (i = 0; i < NHANDLES; ++i)
    if (handle_name[i] != NULL)
      {
        dup2 (handle_saved[i], i);
        close (handle_saved[i]);
      }

  free (copy);
  free (nargv);

  if (pid < 0)
    perror_with_name ("spawnve");

  /* Now that we have a child process, make it our target, and
     initialize anything target-vector-specific that needs initializing.  */
  (*init_trace_fun)(pid);

#ifdef CREATE_INFERIOR_HOOK
  CREATE_INFERIOR_HOOK (pid);
#endif  
  inferior_pid = pid;
  clear_proceed_status ();
  init_wait_for_inferior ();
  target_terminal_init ();
  target_terminal_inferior ();
  stop_soon_quietly = 0;
}
