/* GDBRX - gdb/REXX interface */

/* Originally written by Anthony Green <green%roboco@cs.toronto.edu>,
   modified by Eberhard Mattes <mattes@azu.informatik.uni-stuttgart.de> */

#include <stdio.h>
#include <stdlib.h>
#include <setjmp.h>
#include <fcntl.h>

#define INCL_REXXSAA
#include <os2emx.h>

#include "defs.h"
#include "inferior.h"
extern void execute_command PARAMS ((char *, int));

FILE *gdbrxStream = NULL;

static char const message[] = "\
GDBRX 1.2 - Anthony T. Green <green@roboco.uucp>\n\
\n\
GDBRX adds a REXX command to gdb, and a gdb subcommand handler to REXX\n\
(gdb) rexx say 'Hello World!'    <-- Everything after 'rexx' is\n\
Hello World!                         interpreted by the REXX interpreter.\n\
\n\
(gdb) rx parse source temp; say temp   <-- 'rx' is an alias for 'rexx'.\n\
OS/2 COMMAND GDBRX_Command\n\
\n\
(gdb) rx call myprog             <-- Calls REXX procedure 'myprog'.\n\
\n\
Note: Single quotes only!\n\n";


static int gdb_rx (char *cmd)
{
  execute_command (cmd, 0);

  /* Do any commands attached to breakpoint we stopped at.  */
  bpstat_do_actions (&stop_bpstat);
}


ULONG GDBRX (PRXSTRING prxsCommand, PUSHORT pusFlags, PRXSTRING prxsResult)
{
  int i, length, linefeeds;
  char *str;
  PCH d;

  prxsCommand->strptr[prxsCommand->strlength] = '\000';

  gdbrxStream = _mfopen (NULL, "wb", 512, -2);

  catch_errors (gdb_rx, (char *)prxsCommand->strptr,
                "Error while executing REXX procedure", RETURN_MASK_ALL);

  *pusFlags = RXSUBCOM_OK;

  length = ftell (gdbrxStream);
  str = _mfclose (gdbrxStream);
  gdbrxStream = NULL;

  linefeeds = _memcount (str, '\n', length);

  if (length + linefeeds > RXAUTOBUFLEN)
    {
      ULONG rc;
      void *newstr;

      rc = DosAllocMem (&newstr, length + linefeeds,
                        PAG_READ|PAG_WRITE|PAG_COMMIT);
      if (rc != 0)
        length = 0;
      else
        prxsResult->strptr = newstr;
    }

  d = prxsResult->strptr;
  for (i = 0; i < length; ++i)
    {
      if (str[i] == '\n' && (i == 0 || str[i-1] != '\r'))
        *d++ = '\r';
      *d++ = str[i];
    }
  prxsResult->strlength = d - prxsResult->strptr;
  free (str);

  return 0;
}

void rexx_command (char *exp, int from_tty)
{
  LONG return_code;
  RXSTRING retstr;
  RXSTRING inStore[2];
  ULONG rc;
  SHORT src;

  if (!exp || stricmp (exp, "help") == 0 || stricmp (exp, "?") == 0)
    {
      printf (message);
      return;
    }

  retstr.strptr = NULL;
  retstr.strlength = 0;

  inStore[0].strptr = malloc (strlen (exp) + 13);
  strcpy (inStore[0].strptr, "INTERPRET \"");
  strcat (inStore[0].strptr, exp);
  strcat (inStore[0].strptr, "\"");
  inStore[0].strlength = strlen (inStore[0].strptr);

  inStore[1].strptr = NULL;
  inStore[1].strlength = 0;

  return_code = RexxStart (0, NULL, "GDBRX_Command", inStore, 
                           "GDBRX", RXCOMMAND, NULL, &src, &retstr);

  if (inStore[1].strptr != NULL)
    DosFreeMem (inStore[1].strptr);
  free (inStore[0].strptr);

  if (return_code == 0)
    {
      if (retstr.strptr)
        {
          retstr.strptr[retstr.strlength] = '\000';
          puts (retstr.strptr);
          DosFreeMem (retstr.strptr);
        }
    }
}


_initialize_rexx ()
{
  ULONG rc;

  if (_osmode == DOS_MODE)
    return;

  rc = RexxRegisterSubcomExe ("GDBRX", (PFN)GDBRX, NULL);
  if (rc != RXSUBCOM_OK && rc != RXSUBCOM_DUP)
    {
      printf ("Error: could not register subcommand handler with REXX (%lu)\n",
              rc);
      return;
    }
  add_com ("rexx", class_obscure, rexx_command,
           "Execute REXX commands. GDBRX is the default subcommand handler.\n"
           "Commands passed to GDBRX will be evaluated by GDB.\n");
  add_com_alias ("rx", "rexx", class_obscure, 1);
}
