/* Native-dependent code for OS/2
   Copyright 1995-1996 Eberhard Mattes.

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.  */

#define INCL_DOSPROCESS
#define INCL_DOSMODULEMGR
#define INCL_DOSFILEMGR
#define INCL_DOSSESMGR
#include <os2.h>
#include <stdio.h>
#include <stdlib.h>
#include <process.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "emx-nat.h"

extern void warning (char *, ...);


int emx_this_vio (void)
{
  TIB *ptib;
  PIB *ppib;

  if (_osmode != OS2_MODE)
    return 0;
  if (DosGetInfoBlocks (&ptib, &ppib) != 0)
    return 1;
  return ppib->pib_ultype != 0;
}


int emx_is_pm (char *p)
{
  ULONG rc, flags;

  if (_osmode != OS2_MODE)
    return 0;
  if (DosQueryAppType (p, &flags) != 0)
    return 0;
  return (flags & FAPPTYP_EXETYPE) == FAPPTYP_WINDOWAPI;
}


static FILE *my_tmp (char *name, size_t name_size, const char *dir)
{
  char tmp[_MAX_PATH];
  int fd;
  FILE *f;

  if (dir == NULL)
    return NULL;
  _makepath (tmp, NULL, dir, "gdXXXXXX", NULL);
  _fnslashify (tmp);
  if (_abspath (name, tmp, name_size) != 0)
    return NULL;
  fd = open (name, O_WRONLY | O_CREAT | O_EXCL | O_TEXT, S_IREAD | S_IWRITE);
  if (fd == -1)
    return NULL;
  f = fdopen (fd, "wt");
  if (f == NULL)
    {
      close (fd);
      return NULL;
    }
  return f;
}


int os2_debug_descendant (int pid, char *name, struct desc *pdesc,
                          unsigned long fork_addr)
{
  char gdb[260], cmd[260];
  char **argv, *options, **opt_vec;
  int gdb_pid, spawn_mode, i, argc, count;
  FILE *f;

  if (pdesc->mode == DD_CONT)
    return 1;

  /* Cannot start GDB for PM program because session switching does
     not work. (Printing a warning would cause a deadlock.) */

  if (emx_is_pm (name))
    return 0;

  if (_execname (gdb, sizeof (gdb)) != 0)
    strcpy (gdb, "gdb.exe");

  f = my_tmp (cmd, sizeof (cmd), getenv ("TMP"));
  if (f == NULL)
    f = my_tmp (cmd, sizeof (cmd), getenv ("TEMP"));
  if (f == NULL)
    f = my_tmp (cmd, sizeof (cmd), getenv ("TMPDIR"));
  if (f == NULL)
    f = my_tmp (cmd, sizeof (cmd), ".");
  if (f == NULL)
    {
      warning ("Cannot create temporary command file.\n");
      return 0;
    }
  fprintf (f, "file %s\n", name);
  fprintf (f, "attach %d\n", pid);
  if (fork_addr != 0 && !pdesc->init)
    {
      fprintf (f, "tbreak *0x%x\n", fork_addr);
      fprintf (f, "continue\n");
    }
  if (fclose (f) != 0)
    {
      warning ("Cannot write temporary command file.\n");
      return 0;
    }

  opt_vec = NULL;
  if (pdesc->options[0] != 0)
    {
      options = alloca (strlen (pdesc->options) + 1);
      strcpy (options, pdesc->options);
      opt_vec = _splitargs (options, &count);
    }
  if (opt_vec == NULL)
    count = 0;

  argv = alloca ((4 + count) * sizeof (*argv));
  argc = 0;
  argv[argc++] = gdb;
  argv[argc++] = "--temp-command";
  argv[argc++] = cmd;
  for (i = 0; i < count; ++i)
    argv[argc++] = opt_vec[i];
  argv[argc++] = NULL;
  free (opt_vec);

  spawn_mode = P_SESSION | P_FOREGROUND | P_UNRELATED;
  if (pdesc->mode == DD_GDB_FS)
    spawn_mode |= P_FULLSCREEN;
  else
    spawn_mode |= P_WINDOWED;

  gdb_pid = spawnv (spawn_mode, gdb, argv);
  if (gdb_pid == -1)
    {
      warning ("Cannot run GDB for descendant process.\n");
      return 0;
    }
  return 1;
}
