Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
* [RFC] Interpreters (~final) (fwd)
@ 2002-09-06  8:40 Keith Seitz
  2002-09-22 15:40 ` Elena Zannoni
  0 siblings, 1 reply; 16+ messages in thread
From: Keith Seitz @ 2002-09-06  8:40 UTC (permalink / raw)
  To: gdb-patches

[-- Attachment #1: Type: TEXT/PLAIN, Size: 2258 bytes --]

Ping.

Last merge of trunk into kseitz_interps-20020528-branch was done on 29 Aug 
2002.
---------- Forwarded message ----------
Date: Tue, 27 Aug 2002 09:17:10 -0700 (PDT)
From: Keith Seitz <keiths@redhat.com>
To: gdb-patches@sources.redhat.com
Subject: [RFC] Interpreters (~final) (fwd)

Ping.

---------- Forwarded message ----------
Date: Tue, 13 Aug 2002 13:22:46 -0700 (PDT)
From: Keith Seitz <keiths@redhat.com>
To: gdb-patches@sources.redhat.com
Subject: [RFC] Interpreters (~final)

Hi,

Well, at long last, I think I am ready to try and get some of this work 
approved.

So, first on the chopping block: interps.c, interps.h.

ChangeLogs (to be massaged appropriately):
2002-08-13  Keith Seitz  <keiths@redhat.com>

        * interps.c (_initialize_interpreter): Remove ability to set
        the interpreter. This could really undermine MI clients.
        * top.c (catcher): Don't worry about interpreter changes.

2002-08-12  Keith Seitz  <keiths@redhat.com>

        * interps.c (_initialize_interpreter): Add completer function
        to "set interpreter" command.

2002-08-12  Keith Seitz  <keiths@redhat.com>

        * interps.c: Run through gdb_indent.sh
        * interps.h: Ditto.

2002-06-24  Keith Seitz  <keiths@redhat.com>

        * interps.c: Include gdb-events.h.
        (clear_interpreter_hooks): Also clear out event handlers.
        (gdb_set_interpreter): Clear out any hooks/event handlers that
        may have been installed by old interpreter.

2002-06-18  Keith Seitz  <keiths@redhat.com>

        * interps.h: Add GDB_INTERPRETER_MI1. GDB_INTERPRETER_MI will
        now be mi version 2.

2002-05-28  Keith Seitz  <keiths@redhat.com>

        * interps.c: New file. (Originally called interpreter.c by Apple)
        * interps.h: New file. (Originally called interpreter.h by Apple)

"Patch"
See appeneded files, interps.h and interps.c

For the curious, you can play with the whole thing by checking out 
kseitz_interps-20020528-branch, which was last merged with cvs HEAD on 9 
Aug 2002. The branch contains testcases, documentation, etc, too.

It probably isn't perfect, but it's at least a place to start (IMO). There 
are no regressions with this compared to gdb of 9 Aug 2002.

Questions/comments welcome.
Keith

[-- Attachment #2: Type: TEXT/PLAIN, Size: 3105 bytes --]

/* Manages interpreters for gdb.
   Copyright 2000,2002 Free Software Foundation, Inc.
   Written by Jim Ingham <jingham@apple.com> of Apple Computer, Inc.

   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., 59 Temple Place - Suite 330,
   Boston, MA 02111-1307, USA. */

#ifndef GDB_INTERPRETER_H
#define GDB_INTERPRETER_H

typedef int (*interp_init_ftype) (void *data);
typedef int (*interp_resume_ftype) (void *data);
typedef int (*interp_do_one_event_ftype) (void *data);
typedef int (*interp_suspend_ftype) (void *data);
typedef int (*interp_delete_ftype) (void *data);
typedef int (*interp_prompt_ftype) (void *data, char *new_prompt);
typedef int (*interp_exec_ftype) (void *data, char *command);

struct ui_out;
struct gdb_interpreter;

struct gdb_interpreter_procs
{
  interp_init_ftype init_proc;
  interp_resume_ftype resume_proc;
  interp_do_one_event_ftype do_one_event_proc;
  interp_suspend_ftype suspend_proc;
  interp_delete_ftype delete_proc;
  interp_exec_ftype exec_proc;
  interp_prompt_ftype prompt_proc;
};

extern struct gdb_interpreter
  *gdb_new_interpreter (char *name, void *data, struct ui_out *uiout,
			struct gdb_interpreter_procs *procs);

extern int gdb_add_interpreter (struct gdb_interpreter *interp);
extern int gdb_delete_interpreter (struct gdb_interpreter *interp);
extern int gdb_set_interpreter (struct gdb_interpreter *interp);
extern struct gdb_interpreter *gdb_lookup_interpreter (char *name);
extern struct gdb_interpreter *gdb_current_interpreter ();
extern struct ui_out *gdb_interpreter_ui_out (struct gdb_interpreter *interp);
extern int gdb_current_interpreter_is_named (char *interp_name);
extern int gdb_interpreter_exec (char *command_str);
extern int gdb_interpreter_display_prompt (char *new_prompt);
extern int gdb_interpreter_set_quiet (struct gdb_interpreter *interp,
				      int quiet);
extern int gdb_interpreter_is_quiet (struct gdb_interpreter *interp);
extern struct gdb_interpreter_procs *gdb_interpreter_get_procs (struct
								gdb_interpreter
								*interp);
extern void *gdb_interpreter_get_data (struct gdb_interpreter *interp);
extern int interpreter_do_one_event ();

void clear_interpreter_hooks ();

/* well-known interpreters */
#define GDB_INTERPRETER_CONSOLE		"console"
#define GDB_INTERPRETER_MI0		"mi0"
#define GDB_INTERPRETER_MI1             "mi1"
#define GDB_INTERPRETER_MI		"mi"
#endif /* GDB_INTERPRETER_H */

[-- Attachment #3: Type: TEXT/PLAIN, Size: 18515 bytes --]

/* Manages interpreters for gdb.
   Copyright 2000, 2002 Free Software Foundation, Inc.
   Written by Jim Ingham <jingham@apple.com> of Apple Computer, Inc.

   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., 59 Temple Place - Suite 330,
   Boston, MA 02111-1307, USA. */

/* This is just a first cut at separating out the "interpreter" functions
   of gdb into self-contained modules.  There are a couple of open areas that
   need to be sorted out:

   1) The interpreter explicitly contains a UI_OUT, and can insert itself
   into the event loop, but it doesn't explicitly contain hooks for readline.
   I did this because it seems to me many interpreters won't want to use
   the readline command interface, and it is probably simpler to just let
   them take over the input in their resume proc.  

   2) The event loop insertion is probably wrong.  I just inserted a 
   do_one_event alongside gdb's do_one_event.  This probably will lead
   to one or the other event loop getting starved.  It would be better
   to provide conversion functions for the gdb file handlers, and when
   an interpreter starts up, it grabs all the gdb created file handlers
   and inserts them into its select.  This is more complicated, however,
   and I have run out of time for now.
*/

#include "defs.h"
#include "gdbcmd.h"
#include "ui-out.h"
#include "event-loop.h"
#include "event-top.h"
#include "interps.h"
#include "completer.h"
#include "gdb_string.h"
#include "gdb-events.h"

struct gdb_interpreter
{
  char *name;			/* This is the name in "-i=" and set interpreter. */
  struct gdb_interpreter *next;	/* Interpreters are stored in a linked list, 
				   this is the next one... */
  void *data;			/* This is a cookie that the instance of the 
				   interpreter can use, for instance to call 
				   itself in hook functions */
  int inited;			/* Has the init_proc been run? */
  struct ui_out *interpreter_out;	/* This is the ui_out used to collect 
					   results for this interpreter.  It can 
					   be a formatter for stdout, as is the 
					   case for the console & mi outputs, or it 
					   might be a result formatter. */
  struct gdb_interpreter_procs procs;
  int quiet_p;
};

/* Functions local to this file. */
static void initialize_interps (void);

static void set_interpreter_cmd (char *args, int from_tty,
				 struct cmd_list_element *c);
static void list_interpreter_cmd (char *args, int from_tty);
static void do_set_interpreter (int not_an_fd);
static char **interpreter_completer (char *text, char *word);

/* The magic initialization routine for this module. */

void _initialize_interpreter (void);

/* Variables local to this file: */

static struct gdb_interpreter *interp_list = NULL;
static struct gdb_interpreter *current_interpreter = NULL;

static int interpreter_initialized = 0;

/* gdb_new_interpreter - This allocates space for a new interpreter,
   fills the fields from the inputs, and returns a pointer to the
   interpreter. */

struct gdb_interpreter *
gdb_new_interpreter (char *name,
		     void *data,
		     struct ui_out *uiout,
		     struct gdb_interpreter_procs *procs)
{
  struct gdb_interpreter *new_interp;

  new_interp =
    (struct gdb_interpreter *) xmalloc (sizeof (struct gdb_interpreter));

  new_interp->name = xstrdup (name);
  new_interp->data = data;
  new_interp->interpreter_out = uiout;
  new_interp->quiet_p = 0;
  new_interp->procs.init_proc = procs->init_proc;
  new_interp->procs.resume_proc = procs->resume_proc;
  new_interp->procs.do_one_event_proc = procs->do_one_event_proc;
  new_interp->procs.suspend_proc = procs->suspend_proc;
  new_interp->procs.delete_proc = procs->delete_proc;
  new_interp->procs.exec_proc = procs->exec_proc;
  new_interp->procs.prompt_proc = procs->prompt_proc;
  new_interp->inited = 0;

  return new_interp;
}

/* Add interpreter INTERP to the gdb interpreter list.  If an
   interpreter of the same name is already on the list, then
   the new one is NOT added, and the function returns 0.  Otherwise
   it returns 1. */

int
gdb_add_interpreter (struct gdb_interpreter *interp)
{
  if (!interpreter_initialized)
    initialize_interps ();

  if (gdb_lookup_interpreter (interp->name) != NULL)
    return 0;

  interp->next = interp_list;
  interp_list = interp;

  return 1;
}

/* Looks for the interpreter INTERP in the interpreter list.  If it exists,
   runs the delete_proc, and if this is successful, the INTERP is deleted from
   the interpreter list and the function returns 1.  If the delete_proc fails, the
   function returns -1 and the interpreter is NOT removed from the list.  If the
   interp is not found, 0 is returned. */

int
gdb_delete_interpreter (struct gdb_interpreter *interp)
{
  struct gdb_interpreter *cur_ptr, *prev_ptr;

  if (!interpreter_initialized)
    {
      ui_out_message (uiout, 0,
		      "You can't delete an interp before you have added one!");
      return -1;
    }

  if (interp_list == NULL)
    {
      ui_out_message (uiout, 0, "No interpreters to delete.");
      return -1;
    }

  if (interp_list->next == NULL)
    {
      ui_out_message (uiout, 0, "You can't delete gdb's only intepreter.");
      return -1;
    }

  for (cur_ptr = interp_list, prev_ptr = NULL;
       cur_ptr != NULL; prev_ptr = cur_ptr, cur_ptr = cur_ptr->next)
    {
      if (cur_ptr == interp)
	{
	  /* Can't currently delete the console interpreter... */
	  if (strcmp (interp->name, "console") == 0)
	    {
	      ui_out_message (uiout, 0,
			      "You can't delete the console interpreter.");
	      return -1;
	    }

	  /* If the interpreter is the current interpreter, switch
	     back to the console interpreter */

	  if (interp == current_interpreter)
	    {
	      gdb_set_interpreter (gdb_lookup_interpreter ("console"));
	    }

	  /* Don't delete the interpreter if its delete proc fails */

	  if ((interp->procs.delete_proc != NULL)
	      && (!interp->procs.delete_proc (interp->data)))
	    return -1;

	  if (cur_ptr == interp_list)
	    interp_list = cur_ptr->next;
	  else
	    prev_ptr->next = cur_ptr->next;

	  break;
	}
    }

  if (cur_ptr == NULL)
    return 0;
  else
    return 1;
}

/* This sets the current interpreter to be INTERP.  If INTERP has not
   been initialized, then this will also run the init proc.  If the
   init proc is successful, return 1, if it fails, set the old
   interpreter back in place and return 0.  If we can't restore the
   old interpreter, then raise an internal error, since we are in
   pretty bad shape at this point. */

int
gdb_set_interpreter (struct gdb_interpreter *interp)
{
  struct gdb_interpreter *old_interp = current_interpreter;
  int first_time = 0;


  char buffer[64];

  if (current_interpreter != NULL)
    {
      do_all_continuations ();
      ui_out_flush (uiout);
      if (current_interpreter->procs.suspend_proc
	  && !current_interpreter->procs.suspend_proc (current_interpreter->
						       data))
	{
	  error ("Could not suspend interpreter \"%s\"\n",
		 current_interpreter->name);
	}
    }
  else
    {
      first_time = 1;
    }

  current_interpreter = interp;

  /* We use interpreter_p for the "set interpreter" variable, so we need
     to make sure we have a malloc'ed copy for the set command to free. */
  if (interpreter_p != NULL
      && strcmp (current_interpreter->name, interpreter_p) != 0)
    {
      xfree (interpreter_p);

      interpreter_p = xstrdup (current_interpreter->name);
    }

  uiout = interp->interpreter_out;

  /* Run the init proc.  If it fails, try to restore the old interp. */

  if (!interp->inited)
    {
      if (interp->procs.init_proc != NULL)
	{
	  if (!interp->procs.init_proc (interp->data))
	    {
	      if (!gdb_set_interpreter (old_interp))
		internal_error (__FILE__, __LINE__,
				"Failed to initialize new interp \"%s\" %s",
				interp->name,
				"and could not restore old interp!\n");
	      return 0;
	    }
	  else
	    {
	      interp->inited = 1;
	    }
	}
      else
	{
	  interp->inited = 1;
	}
    }

  /* Clear out any installed interpreter hooks/event handlers. */
  clear_interpreter_hooks ();

  if (interp->procs.resume_proc != NULL
      && (!interp->procs.resume_proc (interp->data)))
    {
      if (!gdb_set_interpreter (old_interp))
	internal_error (__FILE__, __LINE__,
			"Failed to initialize new interp \"%s\" %s",
			interp->name, "and could not restore old interp!\n");
      return 0;
    }

  /* Finally, put up the new prompt to show that we are indeed here. 
     Also, display_gdb_prompt for the console does some readline magic
     which is needed for the console interpreter, at least... */

  if (!first_time)
    {
      if (!gdb_interpreter_is_quiet (interp))
	{
	  sprintf (buffer, "Switching to interpreter \"%.24s\".\n",
		   interp->name);
	  ui_out_text (uiout, buffer);
	}
      display_gdb_prompt (NULL);
    }

  return 1;
}

/*
 * gdb_lookup_interpreter - Looks up the interpreter for NAME.  If
 * no such interpreter exists, return NULL, otherwise return a pointer
 * to the interpreter. 
 */

struct gdb_interpreter *
gdb_lookup_interpreter (char *name)
{
  struct gdb_interpreter *interp;

  if (name == NULL || strlen (name) == 0)
    return NULL;

  for (interp = interp_list; interp != NULL; interp = interp->next)
    {
      if (strcmp (interp->name, name) == 0)
	return interp;
    }

  return NULL;
}

/* Returns the current interpreter. */

struct gdb_interpreter *
gdb_current_interpreter ()
{
  return current_interpreter;
}

struct ui_out *
gdb_interpreter_ui_out (struct gdb_interpreter *interp)
{
  if (interp != NULL)
    return interp->interpreter_out;

  return current_interpreter->interpreter_out;
}

/* Returns true if the current interp is the passed in name. */
int
gdb_current_interpreter_is_named (char *interp_name)
{
  struct gdb_interpreter *current_interp = gdb_current_interpreter ();

  if (current_interp)
    return (strcmp (current_interp->name, interp_name) == 0);

  return 0;
}

/* This is called in display_gdb_prompt.
   If the current interpreter defines a prompt_proc, then that proc is 
   run.  If the proc returns a non-zero value, display_gdb_prompt will
   return without itself displaying the prompt. */

int
gdb_interpreter_display_prompt (char *new_prompt)
{
  if (current_interpreter->procs.prompt_proc == NULL)
    return 0;
  else
    return current_interpreter->procs.prompt_proc (current_interpreter->data,
						   new_prompt);
}

int
gdb_interpreter_is_quiet (struct gdb_interpreter *interp)
{
  if (interp != NULL)
    return interp->quiet_p;
  else
    return current_interpreter->quiet_p;
}

int
gdb_interpreter_set_quiet (struct gdb_interpreter *interp, int quiet)
{
  int old_val = interp->quiet_p;
  interp->quiet_p = quiet;
  return old_val;
}

/* gdb_interpreter_exec - This executes COMMAND_STR in the current 
   interpreter. */

int
gdb_interpreter_exec (char *command_str)
{
  if (current_interpreter->procs.exec_proc != NULL)
    {
      return current_interpreter->procs.exec_proc (current_interpreter->data,
						   command_str);
    }

  return 0;
}

struct gdb_interpreter_procs *
gdb_interpreter_get_procs (struct gdb_interpreter *interp)
{
  if (interp != NULL)
    return &interp->procs;

  return &current_interpreter->procs;
}

void *
gdb_interpreter_get_data (struct gdb_interpreter *interp)
{
  if (interp != NULL)
    return interp->data;

  return current_interpreter->data;
}

int
interpreter_do_one_event ()
{
  if (current_interpreter->procs.do_one_event_proc == NULL)
    return 0;

  return current_interpreter->procs.do_one_event_proc (current_interpreter->
						       data);
}

/* A convenience routine that nulls out all the
   common command hooks.  Use it when removing your interpreter in its 
   suspend proc. */

void
clear_interpreter_hooks ()
{
  init_ui_hook = 0;
  print_frame_info_listing_hook = 0;
  /*print_frame_more_info_hook = 0; */
  query_hook = 0;
  warning_hook = 0;
  create_breakpoint_hook = 0;
  delete_breakpoint_hook = 0;
  modify_breakpoint_hook = 0;
  interactive_hook = 0;
  registers_changed_hook = 0;
  readline_begin_hook = 0;
  readline_hook = 0;
  readline_end_hook = 0;
  register_changed_hook = 0;
  memory_changed_hook = 0;
  context_hook = 0;
  target_wait_hook = 0;
  call_command_hook = 0;
  error_hook = 0;
  error_begin_hook = 0;
  command_loop_hook = 0;
  clear_gdb_event_hooks ();
}

/* This is a lazy init routine, called the first time
   the interpreter module is used.  I put it here just in case, but I haven't
   thought of a use for it yet.  I will probably bag it soon, since I don't
   think it will be necessary. */

static void
initialize_interps (void)
{
  interpreter_initialized = 1;
  /* Don't know if anything needs to be done here... */
}

/* set_interpreter_cmd - This implements "set interpreter foo". */

static void
set_interpreter_cmd (char *args, int from_tty, struct cmd_list_element *c)
{
  struct gdb_interpreter *interp_ptr;

  dont_repeat ();

  if (cmd_type (c) != set_cmd)
    return;

  interp_ptr = gdb_lookup_interpreter (interpreter_p);
  if (interp_ptr != NULL)
    {
      if (!gdb_set_interpreter (interp_ptr))
	error ("\nCould not switch to interpreter \"%s\", %s%s\".\n",
	       interp_ptr->name, "reverting to interpreter \"",
	       current_interpreter->name);
    }
  else
    {
      char *bad_name = interpreter_p;
      interpreter_p = xstrdup (current_interpreter->name);
      error ("Could not find interpreter \"%s\".", bad_name);
    }
}

/* list_interpreter_cmd - This implements "info interpreters". */

void
list_interpreter_cmd (char *args, int from_tty)
{
  struct gdb_interpreter *interp_ptr;

  ui_out_list_begin (uiout, "interpreters");
  for (interp_ptr = interp_list; interp_ptr != NULL;
       interp_ptr = interp_ptr->next)
    {
      ui_out_text (uiout, "  * ");
      ui_out_field_string (uiout, "interpreter", interp_ptr->name);
      ui_out_text (uiout, "\n");
    }
  ui_out_list_end (uiout);
}

void
interpreter_exec_cmd (char *args, int from_tty)
{
  struct gdb_interpreter *old_interp, *interp_to_use;
  char **prules = NULL;
  char **trule = NULL;
  unsigned int nrules;
  unsigned int i;
  int old_quiet;

  prules = buildargv (args);
  if (prules == NULL)
    {
      error ("unable to parse arguments");
    }

  nrules = 0;
  if (prules != NULL)
    {
      for (trule = prules; *trule != NULL; trule++)
	{
	  nrules++;
	}
    }

  if (nrules < 2)
    error ("usage: interpreter-exec <interpreter> [ <command> ... ]");

  old_interp = gdb_current_interpreter ();

  interp_to_use = gdb_lookup_interpreter (prules[0]);
  if (interp_to_use == NULL)
    error ("Could not find interpreter \"%s\".", prules[0]);

  old_quiet = gdb_interpreter_set_quiet (interp_to_use, 1);

  if (!gdb_set_interpreter (interp_to_use))
    error ("Could not switch to interpreter \"%s\".", prules[0]);

  for (i = 1; i < nrules; i++)
    {
      if (!gdb_interpreter_exec (prules[i]))
	{
	  gdb_set_interpreter (old_interp);
	  gdb_interpreter_set_quiet (interp_to_use, old_quiet);
	  error
	    ("interpreter-exec: mi_interpreter_execute: error in command: \"%s\".",
	     prules[i]);
	  break;
	}
    }

  gdb_set_interpreter (old_interp);
  gdb_interpreter_set_quiet (interp_to_use, old_quiet);
}

/* List the possible interpreters which could complete the given text. */

static char **
interpreter_completer (char *text, char *word)
{
  int alloced, textlen;
  int num_matches;
  char **matches;
  struct gdb_interpreter *interp;

  /* We expect only a very limited number of interpreters, so just
     allocate room for all of them. */
  for (interp = interp_list; interp != NULL; interp = interp->next)
    ++alloced;
  matches = (char **) xmalloc (alloced * sizeof (char *));

  num_matches = 0;
  textlen = strlen (text);
  for (interp = interp_list; interp != NULL; interp = interp->next)
    {
      if (strncmp (interp->name, text, textlen) == 0)
	{
	  matches[num_matches] =
	    (char *) xmalloc (strlen (word) + strlen (interp->name) + 1);
	  if (word == text)
	    strcpy (matches[num_matches], interp->name);
	  else if (word > text)
	    {
	      /* Return some portion of interp->name */
	      strcpy (matches[num_matches], interp->name + (word - text));
	    }
	  else
	    {
	      /* Return some of text plus interp->name */
	      strncpy (matches[num_matches], word, text - word);
	      matches[num_matches][text - word] = '\0';
	      strcat (matches[num_matches], interp->name);
	    }
	  ++num_matches;
	}
    }

  if (num_matches == 0)
    {
      xfree (matches);
      matches = NULL;
    }
  else if (num_matches < alloced)
    {
      matches = (char **) xrealloc ((char *) matches, ((num_matches + 1)
						       * sizeof (char *)));
      matches[num_matches] = NULL;
    }

  return matches;
}

/* This just adds the "set interpreter" and "info interpreters" commands. */

void
_initialize_interpreter (void)
{
  struct cmd_list_element *c;

  c = add_cmd ("interpreter-exec", class_support,
	       interpreter_exec_cmd,
	       "Execute a command in an interpreter.  It takes two arguments:\n\
The first argument is the name of the interpreter to use.\n\
The second argument is the command to execute.\n", &cmdlist);
  set_cmd_completer (c, interpreter_completer);
}

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [RFC] Interpreters (~final) (fwd)
  2002-09-06  8:40 [RFC] Interpreters (~final) (fwd) Keith Seitz
@ 2002-09-22 15:40 ` Elena Zannoni
  2002-09-23 11:57   ` Keith Seitz
  0 siblings, 1 reply; 16+ messages in thread
From: Elena Zannoni @ 2002-09-22 15:40 UTC (permalink / raw)
  To: Keith Seitz; +Cc: gdb-patches

Keith Seitz writes:
 > Ping.
 > 

At last....

OK, it seems innocuous enough, but I miss to see how it interacts with
the event loop and the rest of gdb. I compiled it (modified the
Makefile.in) and noticed a warning with alloced initialized. It should
be initialized to 0.

Can you just post the bare minimum that will make the MI accept
interpreter-exec? Even if it won't be able to do much?
We can trim the testsuite file down to what passes, if necessary.

Thanks
Elena

 > Last merge of trunk into kseitz_interps-20020528-branch was done on 29 Aug 
 > 2002.
 > ---------- Forwarded message ----------
 > Date: Tue, 27 Aug 2002 09:17:10 -0700 (PDT)
 > From: Keith Seitz <keiths@redhat.com>
 > To: gdb-patches@sources.redhat.com
 > Subject: [RFC] Interpreters (~final) (fwd)
 > 
 > Ping.
 > 
 > ---------- Forwarded message ----------
 > Date: Tue, 13 Aug 2002 13:22:46 -0700 (PDT)
 > From: Keith Seitz <keiths@redhat.com>
 > To: gdb-patches@sources.redhat.com
 > Subject: [RFC] Interpreters (~final)
 > 
 > Hi,
 > 
 > Well, at long last, I think I am ready to try and get some of this work 
 > approved.
 > 
 > So, first on the chopping block: interps.c, interps.h.
 > 
 > ChangeLogs (to be massaged appropriately):
 > 2002-08-13  Keith Seitz  <keiths@redhat.com>
 > 
 >         * interps.c (_initialize_interpreter): Remove ability to set
 >         the interpreter. This could really undermine MI clients.
 >         * top.c (catcher): Don't worry about interpreter changes.
 > 
 > 2002-08-12  Keith Seitz  <keiths@redhat.com>
 > 
 >         * interps.c (_initialize_interpreter): Add completer function
 >         to "set interpreter" command.
 > 
 > 2002-08-12  Keith Seitz  <keiths@redhat.com>
 > 
 >         * interps.c: Run through gdb_indent.sh
 >         * interps.h: Ditto.
 > 
 > 2002-06-24  Keith Seitz  <keiths@redhat.com>
 > 
 >         * interps.c: Include gdb-events.h.
 >         (clear_interpreter_hooks): Also clear out event handlers.
 >         (gdb_set_interpreter): Clear out any hooks/event handlers that
 >         may have been installed by old interpreter.
 > 
 > 2002-06-18  Keith Seitz  <keiths@redhat.com>
 > 
 >         * interps.h: Add GDB_INTERPRETER_MI1. GDB_INTERPRETER_MI will
 >         now be mi version 2.
 > 
 > 2002-05-28  Keith Seitz  <keiths@redhat.com>
 > 
 >         * interps.c: New file. (Originally called interpreter.c by Apple)
 >         * interps.h: New file. (Originally called interpreter.h by Apple)
 > 
 > "Patch"
 > See appeneded files, interps.h and interps.c
 > 
 > For the curious, you can play with the whole thing by checking out 
 > kseitz_interps-20020528-branch, which was last merged with cvs HEAD on 9 
 > Aug 2002. The branch contains testcases, documentation, etc, too.
 > 
 > It probably isn't perfect, but it's at least a place to start (IMO). There 
 > are no regressions with this compared to gdb of 9 Aug 2002.
 > 
 > Questions/comments welcome.
 > Keith
 > /* Manages interpreters for gdb.
 >    Copyright 2000,2002 Free Software Foundation, Inc.
 >    Written by Jim Ingham <jingham@apple.com> of Apple Computer, Inc.
 > 
 >    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., 59 Temple Place - Suite 330,
 >    Boston, MA 02111-1307, USA. */
 > 
 > #ifndef GDB_INTERPRETER_H
 > #define GDB_INTERPRETER_H
 > 
 > typedef int (*interp_init_ftype) (void *data);
 > typedef int (*interp_resume_ftype) (void *data);
 > typedef int (*interp_do_one_event_ftype) (void *data);
 > typedef int (*interp_suspend_ftype) (void *data);
 > typedef int (*interp_delete_ftype) (void *data);
 > typedef int (*interp_prompt_ftype) (void *data, char *new_prompt);
 > typedef int (*interp_exec_ftype) (void *data, char *command);
 > 
 > struct ui_out;
 > struct gdb_interpreter;
 > 
 > struct gdb_interpreter_procs
 > {
 >   interp_init_ftype init_proc;
 >   interp_resume_ftype resume_proc;
 >   interp_do_one_event_ftype do_one_event_proc;
 >   interp_suspend_ftype suspend_proc;
 >   interp_delete_ftype delete_proc;
 >   interp_exec_ftype exec_proc;
 >   interp_prompt_ftype prompt_proc;
 > };
 > 
 > extern struct gdb_interpreter
 >   *gdb_new_interpreter (char *name, void *data, struct ui_out *uiout,
 > 			struct gdb_interpreter_procs *procs);
 > 
 > extern int gdb_add_interpreter (struct gdb_interpreter *interp);
 > extern int gdb_delete_interpreter (struct gdb_interpreter *interp);
 > extern int gdb_set_interpreter (struct gdb_interpreter *interp);
 > extern struct gdb_interpreter *gdb_lookup_interpreter (char *name);
 > extern struct gdb_interpreter *gdb_current_interpreter ();
 > extern struct ui_out *gdb_interpreter_ui_out (struct gdb_interpreter *interp);
 > extern int gdb_current_interpreter_is_named (char *interp_name);
 > extern int gdb_interpreter_exec (char *command_str);
 > extern int gdb_interpreter_display_prompt (char *new_prompt);
 > extern int gdb_interpreter_set_quiet (struct gdb_interpreter *interp,
 > 				      int quiet);
 > extern int gdb_interpreter_is_quiet (struct gdb_interpreter *interp);
 > extern struct gdb_interpreter_procs *gdb_interpreter_get_procs (struct
 > 								gdb_interpreter
 > 								*interp);
 > extern void *gdb_interpreter_get_data (struct gdb_interpreter *interp);
 > extern int interpreter_do_one_event ();
 > 
 > void clear_interpreter_hooks ();
 > 
 > /* well-known interpreters */
 > #define GDB_INTERPRETER_CONSOLE		"console"
 > #define GDB_INTERPRETER_MI0		"mi0"
 > #define GDB_INTERPRETER_MI1             "mi1"
 > #define GDB_INTERPRETER_MI		"mi"
 > #endif /* GDB_INTERPRETER_H */
 > /* Manages interpreters for gdb.
 >    Copyright 2000, 2002 Free Software Foundation, Inc.
 >    Written by Jim Ingham <jingham@apple.com> of Apple Computer, Inc.
 > 
 >    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., 59 Temple Place - Suite 330,
 >    Boston, MA 02111-1307, USA. */
 > 
 > /* This is just a first cut at separating out the "interpreter" functions
 >    of gdb into self-contained modules.  There are a couple of open areas that
 >    need to be sorted out:
 > 
 >    1) The interpreter explicitly contains a UI_OUT, and can insert itself
 >    into the event loop, but it doesn't explicitly contain hooks for readline.
 >    I did this because it seems to me many interpreters won't want to use
 >    the readline command interface, and it is probably simpler to just let
 >    them take over the input in their resume proc.  
 > 
 >    2) The event loop insertion is probably wrong.  I just inserted a 
 >    do_one_event alongside gdb's do_one_event.  This probably will lead
 >    to one or the other event loop getting starved.  It would be better
 >    to provide conversion functions for the gdb file handlers, and when
 >    an interpreter starts up, it grabs all the gdb created file handlers
 >    and inserts them into its select.  This is more complicated, however,
 >    and I have run out of time for now.
 > */
 > 
 > #include "defs.h"
 > #include "gdbcmd.h"
 > #include "ui-out.h"
 > #include "event-loop.h"
 > #include "event-top.h"
 > #include "interps.h"
 > #include "completer.h"
 > #include "gdb_string.h"
 > #include "gdb-events.h"
 > 
 > struct gdb_interpreter
 > {
 >   char *name;			/* This is the name in "-i=" and set interpreter. */
 >   struct gdb_interpreter *next;	/* Interpreters are stored in a linked list, 
 > 				   this is the next one... */
 >   void *data;			/* This is a cookie that the instance of the 
 > 				   interpreter can use, for instance to call 
 > 				   itself in hook functions */
 >   int inited;			/* Has the init_proc been run? */
 >   struct ui_out *interpreter_out;	/* This is the ui_out used to collect 
 > 					   results for this interpreter.  It can 
 > 					   be a formatter for stdout, as is the 
 > 					   case for the console & mi outputs, or it 
 > 					   might be a result formatter. */
 >   struct gdb_interpreter_procs procs;
 >   int quiet_p;
 > };
 > 
 > /* Functions local to this file. */
 > static void initialize_interps (void);
 > 
 > static void set_interpreter_cmd (char *args, int from_tty,
 > 				 struct cmd_list_element *c);
 > static void list_interpreter_cmd (char *args, int from_tty);
 > static void do_set_interpreter (int not_an_fd);
 > static char **interpreter_completer (char *text, char *word);
 > 
 > /* The magic initialization routine for this module. */
 > 
 > void _initialize_interpreter (void);
 > 
 > /* Variables local to this file: */
 > 
 > static struct gdb_interpreter *interp_list = NULL;
 > static struct gdb_interpreter *current_interpreter = NULL;
 > 
 > static int interpreter_initialized = 0;
 > 
 > /* gdb_new_interpreter - This allocates space for a new interpreter,
 >    fills the fields from the inputs, and returns a pointer to the
 >    interpreter. */
 > 
 > struct gdb_interpreter *
 > gdb_new_interpreter (char *name,
 > 		     void *data,
 > 		     struct ui_out *uiout,
 > 		     struct gdb_interpreter_procs *procs)
 > {
 >   struct gdb_interpreter *new_interp;
 > 
 >   new_interp =
 >     (struct gdb_interpreter *) xmalloc (sizeof (struct gdb_interpreter));
 > 
 >   new_interp->name = xstrdup (name);
 >   new_interp->data = data;
 >   new_interp->interpreter_out = uiout;
 >   new_interp->quiet_p = 0;
 >   new_interp->procs.init_proc = procs->init_proc;
 >   new_interp->procs.resume_proc = procs->resume_proc;
 >   new_interp->procs.do_one_event_proc = procs->do_one_event_proc;
 >   new_interp->procs.suspend_proc = procs->suspend_proc;
 >   new_interp->procs.delete_proc = procs->delete_proc;
 >   new_interp->procs.exec_proc = procs->exec_proc;
 >   new_interp->procs.prompt_proc = procs->prompt_proc;
 >   new_interp->inited = 0;
 > 
 >   return new_interp;
 > }
 > 
 > /* Add interpreter INTERP to the gdb interpreter list.  If an
 >    interpreter of the same name is already on the list, then
 >    the new one is NOT added, and the function returns 0.  Otherwise
 >    it returns 1. */
 > 
 > int
 > gdb_add_interpreter (struct gdb_interpreter *interp)
 > {
 >   if (!interpreter_initialized)
 >     initialize_interps ();
 > 
 >   if (gdb_lookup_interpreter (interp->name) != NULL)
 >     return 0;
 > 
 >   interp->next = interp_list;
 >   interp_list = interp;
 > 
 >   return 1;
 > }
 > 
 > /* Looks for the interpreter INTERP in the interpreter list.  If it exists,
 >    runs the delete_proc, and if this is successful, the INTERP is deleted from
 >    the interpreter list and the function returns 1.  If the delete_proc fails, the
 >    function returns -1 and the interpreter is NOT removed from the list.  If the
 >    interp is not found, 0 is returned. */
 > 
 > int
 > gdb_delete_interpreter (struct gdb_interpreter *interp)
 > {
 >   struct gdb_interpreter *cur_ptr, *prev_ptr;
 > 
 >   if (!interpreter_initialized)
 >     {
 >       ui_out_message (uiout, 0,
 > 		      "You can't delete an interp before you have added one!");
 >       return -1;
 >     }
 > 
 >   if (interp_list == NULL)
 >     {
 >       ui_out_message (uiout, 0, "No interpreters to delete.");
 >       return -1;
 >     }
 > 
 >   if (interp_list->next == NULL)
 >     {
 >       ui_out_message (uiout, 0, "You can't delete gdb's only intepreter.");
 >       return -1;
 >     }
 > 
 >   for (cur_ptr = interp_list, prev_ptr = NULL;
 >        cur_ptr != NULL; prev_ptr = cur_ptr, cur_ptr = cur_ptr->next)
 >     {
 >       if (cur_ptr == interp)
 > 	{
 > 	  /* Can't currently delete the console interpreter... */
 > 	  if (strcmp (interp->name, "console") == 0)
 > 	    {
 > 	      ui_out_message (uiout, 0,
 > 			      "You can't delete the console interpreter.");
 > 	      return -1;
 > 	    }
 > 
 > 	  /* If the interpreter is the current interpreter, switch
 > 	     back to the console interpreter */
 > 
 > 	  if (interp == current_interpreter)
 > 	    {
 > 	      gdb_set_interpreter (gdb_lookup_interpreter ("console"));
 > 	    }
 > 
 > 	  /* Don't delete the interpreter if its delete proc fails */
 > 
 > 	  if ((interp->procs.delete_proc != NULL)
 > 	      && (!interp->procs.delete_proc (interp->data)))
 > 	    return -1;
 > 
 > 	  if (cur_ptr == interp_list)
 > 	    interp_list = cur_ptr->next;
 > 	  else
 > 	    prev_ptr->next = cur_ptr->next;
 > 
 > 	  break;
 > 	}
 >     }
 > 
 >   if (cur_ptr == NULL)
 >     return 0;
 >   else
 >     return 1;
 > }
 > 
 > /* This sets the current interpreter to be INTERP.  If INTERP has not
 >    been initialized, then this will also run the init proc.  If the
 >    init proc is successful, return 1, if it fails, set the old
 >    interpreter back in place and return 0.  If we can't restore the
 >    old interpreter, then raise an internal error, since we are in
 >    pretty bad shape at this point. */
 > 
 > int
 > gdb_set_interpreter (struct gdb_interpreter *interp)
 > {
 >   struct gdb_interpreter *old_interp = current_interpreter;
 >   int first_time = 0;
 > 
 > 
 >   char buffer[64];
 > 
 >   if (current_interpreter != NULL)
 >     {
 >       do_all_continuations ();
 >       ui_out_flush (uiout);
 >       if (current_interpreter->procs.suspend_proc
 > 	  && !current_interpreter->procs.suspend_proc (current_interpreter->
 > 						       data))
 > 	{
 > 	  error ("Could not suspend interpreter \"%s\"\n",
 > 		 current_interpreter->name);
 > 	}
 >     }
 >   else
 >     {
 >       first_time = 1;
 >     }
 > 
 >   current_interpreter = interp;
 > 
 >   /* We use interpreter_p for the "set interpreter" variable, so we need
 >      to make sure we have a malloc'ed copy for the set command to free. */
 >   if (interpreter_p != NULL
 >       && strcmp (current_interpreter->name, interpreter_p) != 0)
 >     {
 >       xfree (interpreter_p);
 > 
 >       interpreter_p = xstrdup (current_interpreter->name);
 >     }
 > 
 >   uiout = interp->interpreter_out;
 > 
 >   /* Run the init proc.  If it fails, try to restore the old interp. */
 > 
 >   if (!interp->inited)
 >     {
 >       if (interp->procs.init_proc != NULL)
 > 	{
 > 	  if (!interp->procs.init_proc (interp->data))
 > 	    {
 > 	      if (!gdb_set_interpreter (old_interp))
 > 		internal_error (__FILE__, __LINE__,
 > 				"Failed to initialize new interp \"%s\" %s",
 > 				interp->name,
 > 				"and could not restore old interp!\n");
 > 	      return 0;
 > 	    }
 > 	  else
 > 	    {
 > 	      interp->inited = 1;
 > 	    }
 > 	}
 >       else
 > 	{
 > 	  interp->inited = 1;
 > 	}
 >     }
 > 
 >   /* Clear out any installed interpreter hooks/event handlers. */
 >   clear_interpreter_hooks ();
 > 
 >   if (interp->procs.resume_proc != NULL
 >       && (!interp->procs.resume_proc (interp->data)))
 >     {
 >       if (!gdb_set_interpreter (old_interp))
 > 	internal_error (__FILE__, __LINE__,
 > 			"Failed to initialize new interp \"%s\" %s",
 > 			interp->name, "and could not restore old interp!\n");
 >       return 0;
 >     }
 > 
 >   /* Finally, put up the new prompt to show that we are indeed here. 
 >      Also, display_gdb_prompt for the console does some readline magic
 >      which is needed for the console interpreter, at least... */
 > 
 >   if (!first_time)
 >     {
 >       if (!gdb_interpreter_is_quiet (interp))
 > 	{
 > 	  sprintf (buffer, "Switching to interpreter \"%.24s\".\n",
 > 		   interp->name);
 > 	  ui_out_text (uiout, buffer);
 > 	}
 >       display_gdb_prompt (NULL);
 >     }
 > 
 >   return 1;
 > }
 > 
 > /*
 >  * gdb_lookup_interpreter - Looks up the interpreter for NAME.  If
 >  * no such interpreter exists, return NULL, otherwise return a pointer
 >  * to the interpreter. 
 >  */
 > 
 > struct gdb_interpreter *
 > gdb_lookup_interpreter (char *name)
 > {
 >   struct gdb_interpreter *interp;
 > 
 >   if (name == NULL || strlen (name) == 0)
 >     return NULL;
 > 
 >   for (interp = interp_list; interp != NULL; interp = interp->next)
 >     {
 >       if (strcmp (interp->name, name) == 0)
 > 	return interp;
 >     }
 > 
 >   return NULL;
 > }
 > 
 > /* Returns the current interpreter. */
 > 
 > struct gdb_interpreter *
 > gdb_current_interpreter ()
 > {
 >   return current_interpreter;
 > }
 > 
 > struct ui_out *
 > gdb_interpreter_ui_out (struct gdb_interpreter *interp)
 > {
 >   if (interp != NULL)
 >     return interp->interpreter_out;
 > 
 >   return current_interpreter->interpreter_out;
 > }
 > 
 > /* Returns true if the current interp is the passed in name. */
 > int
 > gdb_current_interpreter_is_named (char *interp_name)
 > {
 >   struct gdb_interpreter *current_interp = gdb_current_interpreter ();
 > 
 >   if (current_interp)
 >     return (strcmp (current_interp->name, interp_name) == 0);
 > 
 >   return 0;
 > }
 > 
 > /* This is called in display_gdb_prompt.
 >    If the current interpreter defines a prompt_proc, then that proc is 
 >    run.  If the proc returns a non-zero value, display_gdb_prompt will
 >    return without itself displaying the prompt. */
 > 
 > int
 > gdb_interpreter_display_prompt (char *new_prompt)
 > {
 >   if (current_interpreter->procs.prompt_proc == NULL)
 >     return 0;
 >   else
 >     return current_interpreter->procs.prompt_proc (current_interpreter->data,
 > 						   new_prompt);
 > }
 > 
 > int
 > gdb_interpreter_is_quiet (struct gdb_interpreter *interp)
 > {
 >   if (interp != NULL)
 >     return interp->quiet_p;
 >   else
 >     return current_interpreter->quiet_p;
 > }
 > 
 > int
 > gdb_interpreter_set_quiet (struct gdb_interpreter *interp, int quiet)
 > {
 >   int old_val = interp->quiet_p;
 >   interp->quiet_p = quiet;
 >   return old_val;
 > }
 > 
 > /* gdb_interpreter_exec - This executes COMMAND_STR in the current 
 >    interpreter. */
 > 
 > int
 > gdb_interpreter_exec (char *command_str)
 > {
 >   if (current_interpreter->procs.exec_proc != NULL)
 >     {
 >       return current_interpreter->procs.exec_proc (current_interpreter->data,
 > 						   command_str);
 >     }
 > 
 >   return 0;
 > }
 > 
 > struct gdb_interpreter_procs *
 > gdb_interpreter_get_procs (struct gdb_interpreter *interp)
 > {
 >   if (interp != NULL)
 >     return &interp->procs;
 > 
 >   return &current_interpreter->procs;
 > }
 > 
 > void *
 > gdb_interpreter_get_data (struct gdb_interpreter *interp)
 > {
 >   if (interp != NULL)
 >     return interp->data;
 > 
 >   return current_interpreter->data;
 > }
 > 
 > int
 > interpreter_do_one_event ()
 > {
 >   if (current_interpreter->procs.do_one_event_proc == NULL)
 >     return 0;
 > 
 >   return current_interpreter->procs.do_one_event_proc (current_interpreter->
 > 						       data);
 > }
 > 
 > /* A convenience routine that nulls out all the
 >    common command hooks.  Use it when removing your interpreter in its 
 >    suspend proc. */
 > 
 > void
 > clear_interpreter_hooks ()
 > {
 >   init_ui_hook = 0;
 >   print_frame_info_listing_hook = 0;
 >   /*print_frame_more_info_hook = 0; */
 >   query_hook = 0;
 >   warning_hook = 0;
 >   create_breakpoint_hook = 0;
 >   delete_breakpoint_hook = 0;
 >   modify_breakpoint_hook = 0;
 >   interactive_hook = 0;
 >   registers_changed_hook = 0;
 >   readline_begin_hook = 0;
 >   readline_hook = 0;
 >   readline_end_hook = 0;
 >   register_changed_hook = 0;
 >   memory_changed_hook = 0;
 >   context_hook = 0;
 >   target_wait_hook = 0;
 >   call_command_hook = 0;
 >   error_hook = 0;
 >   error_begin_hook = 0;
 >   command_loop_hook = 0;
 >   clear_gdb_event_hooks ();
 > }
 > 
 > /* This is a lazy init routine, called the first time
 >    the interpreter module is used.  I put it here just in case, but I haven't
 >    thought of a use for it yet.  I will probably bag it soon, since I don't
 >    think it will be necessary. */
 > 
 > static void
 > initialize_interps (void)
 > {
 >   interpreter_initialized = 1;
 >   /* Don't know if anything needs to be done here... */
 > }
 > 
 > /* set_interpreter_cmd - This implements "set interpreter foo". */
 > 
 > static void
 > set_interpreter_cmd (char *args, int from_tty, struct cmd_list_element *c)
 > {
 >   struct gdb_interpreter *interp_ptr;
 > 
 >   dont_repeat ();
 > 
 >   if (cmd_type (c) != set_cmd)
 >     return;
 > 
 >   interp_ptr = gdb_lookup_interpreter (interpreter_p);
 >   if (interp_ptr != NULL)
 >     {
 >       if (!gdb_set_interpreter (interp_ptr))
 > 	error ("\nCould not switch to interpreter \"%s\", %s%s\".\n",
 > 	       interp_ptr->name, "reverting to interpreter \"",
 > 	       current_interpreter->name);
 >     }
 >   else
 >     {
 >       char *bad_name = interpreter_p;
 >       interpreter_p = xstrdup (current_interpreter->name);
 >       error ("Could not find interpreter \"%s\".", bad_name);
 >     }
 > }
 > 
 > /* list_interpreter_cmd - This implements "info interpreters". */
 > 
 > void
 > list_interpreter_cmd (char *args, int from_tty)
 > {
 >   struct gdb_interpreter *interp_ptr;
 > 
 >   ui_out_list_begin (uiout, "interpreters");
 >   for (interp_ptr = interp_list; interp_ptr != NULL;
 >        interp_ptr = interp_ptr->next)
 >     {
 >       ui_out_text (uiout, "  * ");
 >       ui_out_field_string (uiout, "interpreter", interp_ptr->name);
 >       ui_out_text (uiout, "\n");
 >     }
 >   ui_out_list_end (uiout);
 > }
 > 
 > void
 > interpreter_exec_cmd (char *args, int from_tty)
 > {
 >   struct gdb_interpreter *old_interp, *interp_to_use;
 >   char **prules = NULL;
 >   char **trule = NULL;
 >   unsigned int nrules;
 >   unsigned int i;
 >   int old_quiet;
 > 
 >   prules = buildargv (args);
 >   if (prules == NULL)
 >     {
 >       error ("unable to parse arguments");
 >     }
 > 
 >   nrules = 0;
 >   if (prules != NULL)
 >     {
 >       for (trule = prules; *trule != NULL; trule++)
 > 	{
 > 	  nrules++;
 > 	}
 >     }
 > 
 >   if (nrules < 2)
 >     error ("usage: interpreter-exec <interpreter> [ <command> ... ]");
 > 
 >   old_interp = gdb_current_interpreter ();
 > 
 >   interp_to_use = gdb_lookup_interpreter (prules[0]);
 >   if (interp_to_use == NULL)
 >     error ("Could not find interpreter \"%s\".", prules[0]);
 > 
 >   old_quiet = gdb_interpreter_set_quiet (interp_to_use, 1);
 > 
 >   if (!gdb_set_interpreter (interp_to_use))
 >     error ("Could not switch to interpreter \"%s\".", prules[0]);
 > 
 >   for (i = 1; i < nrules; i++)
 >     {
 >       if (!gdb_interpreter_exec (prules[i]))
 > 	{
 > 	  gdb_set_interpreter (old_interp);
 > 	  gdb_interpreter_set_quiet (interp_to_use, old_quiet);
 > 	  error
 > 	    ("interpreter-exec: mi_interpreter_execute: error in command: \"%s\".",
 > 	     prules[i]);
 > 	  break;
 > 	}
 >     }
 > 
 >   gdb_set_interpreter (old_interp);
 >   gdb_interpreter_set_quiet (interp_to_use, old_quiet);
 > }
 > 
 > /* List the possible interpreters which could complete the given text. */
 > 
 > static char **
 > interpreter_completer (char *text, char *word)
 > {
 >   int alloced, textlen;
 >   int num_matches;
 >   char **matches;
 >   struct gdb_interpreter *interp;
 > 
 >   /* We expect only a very limited number of interpreters, so just
 >      allocate room for all of them. */
 >   for (interp = interp_list; interp != NULL; interp = interp->next)
 >     ++alloced;
 >   matches = (char **) xmalloc (alloced * sizeof (char *));
 > 
 >   num_matches = 0;
 >   textlen = strlen (text);
 >   for (interp = interp_list; interp != NULL; interp = interp->next)
 >     {
 >       if (strncmp (interp->name, text, textlen) == 0)
 > 	{
 > 	  matches[num_matches] =
 > 	    (char *) xmalloc (strlen (word) + strlen (interp->name) + 1);
 > 	  if (word == text)
 > 	    strcpy (matches[num_matches], interp->name);
 > 	  else if (word > text)
 > 	    {
 > 	      /* Return some portion of interp->name */
 > 	      strcpy (matches[num_matches], interp->name + (word - text));
 > 	    }
 > 	  else
 > 	    {
 > 	      /* Return some of text plus interp->name */
 > 	      strncpy (matches[num_matches], word, text - word);
 > 	      matches[num_matches][text - word] = '\0';
 > 	      strcat (matches[num_matches], interp->name);
 > 	    }
 > 	  ++num_matches;
 > 	}
 >     }
 > 
 >   if (num_matches == 0)
 >     {
 >       xfree (matches);
 >       matches = NULL;
 >     }
 >   else if (num_matches < alloced)
 >     {
 >       matches = (char **) xrealloc ((char *) matches, ((num_matches + 1)
 > 						       * sizeof (char *)));
 >       matches[num_matches] = NULL;
 >     }
 > 
 >   return matches;
 > }
 > 
 > /* This just adds the "set interpreter" and "info interpreters" commands. */
 > 
 > void
 > _initialize_interpreter (void)
 > {
 >   struct cmd_list_element *c;
 > 
 >   c = add_cmd ("interpreter-exec", class_support,
 > 	       interpreter_exec_cmd,
 > 	       "Execute a command in an interpreter.  It takes two arguments:\n\
 > The first argument is the name of the interpreter to use.\n\
 > The second argument is the command to execute.\n", &cmdlist);
 >   set_cmd_completer (c, interpreter_completer);
 > }


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [RFC] Interpreters (~final) (fwd)
  2002-09-22 15:40 ` Elena Zannoni
@ 2002-09-23 11:57   ` Keith Seitz
  2002-09-23 12:44     ` Keith Seitz
  0 siblings, 1 reply; 16+ messages in thread
From: Keith Seitz @ 2002-09-23 11:57 UTC (permalink / raw)
  To: Elena Zannoni; +Cc: gdb-patches

On Sun, 22 Sep 2002, Elena Zannoni wrote:

> Can you just post the bare minimum that will make the MI accept
> interpreter-exec? Even if it won't be able to do much?
> We can trim the testsuite file down to what passes, if necessary.

Well, it would be much easier for you to look at the branch listed below, 
but I'll see if I can come up with a patch which adds the minimum. I'm 
afraid that the change is so huge (lots of new files) that the patch is 
going to be unmanageable (and probably the whole thing).

I'll let you know when I have something "simpler".

Keith



^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [RFC] Interpreters (~final) (fwd)
  2002-09-23 11:57   ` Keith Seitz
@ 2002-09-23 12:44     ` Keith Seitz
  2002-09-30 11:35       ` Elena Zannoni
  2002-09-30 15:58       ` Elena Zannoni
  0 siblings, 2 replies; 16+ messages in thread
From: Keith Seitz @ 2002-09-23 12:44 UTC (permalink / raw)
  To: Elena Zannoni; +Cc: gdb-patches

[-- Attachment #1: Type: TEXT/PLAIN, Size: 401 bytes --]

On Mon, 23 Sep 2002, Keith Seitz wrote:

> I'll let you know when I have something "simpler".

Ok, well, it isn't much simpler. I whacked a couple of bug fixes, docs, 
and testsuites. You should be able to run mi-cli.exp with this jumbo 
patch, but you will get a couple of false failures, since I did not 
include the mi-support.exp changes to support async event notifications.

Good luck...
Keith


[-- Attachment #2: Type: TEXT/PLAIN, Size: 83422 bytes --]

Index: Makefile.in
===================================================================
RCS file: /cvs/src/src/gdb/Makefile.in,v
retrieving revision 1.263
diff -p -r1.263 Makefile.in
*** Makefile.in	20 Sep 2002 18:14:49 -0000	1.263
--- Makefile.in	23 Sep 2002 19:37:36 -0000
*************** LIBICONV = @LIBICONV@
*** 145,155 ****
  # CLI sub directory definitons
  #
  SUBDIR_CLI_OBS = \
! 	cli-dump.o \
! 	cli-decode.o cli-script.o cli-cmds.o cli-setshow.o cli-utils.o
  SUBDIR_CLI_SRCS = \
! 	cli/cli-dump.c \
! 	cli/cli-decode.c cli/cli-script.c cli/cli-cmds.c cli/cli-setshow.c \
  	cli/cli-utils.c
  SUBDIR_CLI_DEPS =
  SUBDIR_CLI_INITS = \
--- 145,155 ----
  # CLI sub directory definitons
  #
  SUBDIR_CLI_OBS = \
! 	cli-dump.o cli-decode.o \
! 	cli-interp.o cli-script.o cli-cmds.o cli-setshow.o cli-utils.o
  SUBDIR_CLI_SRCS = \
! 	cli/cli-dump.c cli/cli-decode.c \
! 	cli/cli-interp.c cli/cli-script.c cli/cli-cmds.c cli/cli-setshow.c \
  	cli/cli-utils.c
  SUBDIR_CLI_DEPS =
  SUBDIR_CLI_INITS = \
*************** SUBDIR_CLI_UNINSTALL=
*** 167,179 ****
  SUBDIR_MI_OBS = \
  	mi-out.o mi-console.o \
  	mi-cmds.o mi-cmd-var.o mi-cmd-break.o mi-cmd-stack.o \
! 	mi-cmd-disas.o \
  	mi-main.o mi-parse.o mi-getopt.o
  SUBDIR_MI_SRCS = \
  	mi/mi-out.c mi/mi-console.c \
  	mi/mi-cmds.c \
  	mi/mi-cmd-var.c mi/mi-cmd-break.c mi/mi-cmd-stack.c \
! 	mi/mi-cmd-disas.c \
  	mi/mi-main.c mi/mi-parse.c mi/mi-getopt.c
  SUBDIR_MI_DEPS =
  SUBDIR_MI_INITS = \
--- 167,179 ----
  SUBDIR_MI_OBS = \
  	mi-out.o mi-console.o \
  	mi-cmds.o mi-cmd-var.o mi-cmd-break.o mi-cmd-stack.o \
! 	mi-cmd-disas.o mi-events.o mi-interp.o \
  	mi-main.o mi-parse.o mi-getopt.o
  SUBDIR_MI_SRCS = \
  	mi/mi-out.c mi/mi-console.c \
  	mi/mi-cmds.c \
  	mi/mi-cmd-var.c mi/mi-cmd-break.c mi/mi-cmd-stack.c \
! 	mi/mi-cmd-disas.c mi/mi-events.c mi/mi-interp.c \
  	mi/mi-main.c mi/mi-parse.c mi/mi-getopt.c
  SUBDIR_MI_DEPS =
  SUBDIR_MI_INITS = \
*************** SFILES = ada-exp.y ada-lang.c ada-typepr
*** 540,546 ****
  	findvar.c regcache.c gdbarch.c arch-utils.c gdbtypes.c osabi.c \
  	inf-loop.c infcmd.c inflow.c infrun.c language.c \
  	kod.c kod-cisco.c \
! 	ui-out.c cli-out.c \
  	varobj.c wrapper.c \
  	jv-exp.y jv-lang.c jv-valprint.c jv-typeprint.c \
  	m2-exp.y m2-lang.c m2-typeprint.c m2-valprint.c main.c maint.c \
--- 540,546 ----
  	findvar.c regcache.c gdbarch.c arch-utils.c gdbtypes.c osabi.c \
  	inf-loop.c infcmd.c inflow.c infrun.c language.c \
  	kod.c kod-cisco.c \
! 	ui-out.c cli-out.c interps.c \
  	varobj.c wrapper.c \
  	jv-exp.y jv-lang.c jv-valprint.c jv-typeprint.c \
  	m2-exp.y m2-lang.c m2-typeprint.c m2-valprint.c main.c maint.c \
*************** i386_tdep_h = i386-tdep.h $(osabi_h)
*** 671,676 ****
--- 671,677 ----
  i387_tdep_h = i387-tdep.h
  inf_loop_h = inf-loop.h
  inferior_h = inferior.h $(breakpoint_h) $(target_h)
+ interps_h = interps.h
  jv_lang_h = jv-lang.h
  kod_h = kod.h
  language_h = language.h
*************** cli_utils_h = $(srcdir)/cli/cli-utils.h
*** 747,752 ****
--- 748,754 ----
  # gdb/mi/ headers
  #
  
+ mi_h = $(srcdir)/mi/mi.h
  mi_cmds_h = $(srcdir)/mi/mi-cmds.h
  mi_console_h = $(srcdir)/mi/mi-console.h
  mi_getopt_h = $(srcdir)/mi/mi-getopt.h
*************** COMMON_OBS = version.o blockframe.o brea
*** 841,847 ****
  	dbxread.o coffread.o elfread.o \
  	dwarfread.o dwarf2read.o mipsread.o stabsread.o corefile.o \
  	c-lang.o f-lang.o \
! 	ui-out.o cli-out.o \
  	varobj.o wrapper.o \
  	jv-lang.o jv-valprint.o jv-typeprint.o \
  	m2-lang.o p-lang.o p-typeprint.o p-valprint.o \
--- 843,849 ----
  	dbxread.o coffread.o elfread.o \
  	dwarfread.o dwarf2read.o mipsread.o stabsread.o corefile.o \
  	c-lang.o f-lang.o \
! 	ui-out.o cli-out.o interps.o \
  	varobj.o wrapper.o \
  	jv-lang.o jv-valprint.o jv-typeprint.o \
  	m2-lang.o p-lang.o p-typeprint.o p-valprint.o \
*************** eval.o: eval.c $(defs_h) $(gdb_string_h)
*** 1660,1666 ****
  event-loop.o: event-loop.c $(defs_h) $(event_loop_h) $(event_top_h) \
  	$(gdb_string_h)
  event-top.o: event-top.c $(defs_h) $(top_h) $(inferior_h) $(target_h) \
! 	$(terminal_h) $(event_loop_h) $(event_top_h) $(gdbcmd_h)
  exec.o: exec.c $(defs_h) $(frame_h) $(inferior_h) $(target_h) $(gdbcmd_h) \
  	$(language_h) $(symfile_h) $(objfiles_h) $(completer_h) $(value_h) \
  	$(gdb_string_h) $(gdbcore_h) $(gdb_stat_h) $(xcoffsolib_h)
--- 1662,1668 ----
  event-loop.o: event-loop.c $(defs_h) $(event_loop_h) $(event_top_h) \
  	$(gdb_string_h)
  event-top.o: event-top.c $(defs_h) $(top_h) $(inferior_h) $(target_h) \
! 	$(terminal_h) $(event_loop_h) $(event_top_h) $(gdbcmd_h) $(interps_h)
  exec.o: exec.c $(defs_h) $(frame_h) $(inferior_h) $(target_h) $(gdbcmd_h) \
  	$(language_h) $(symfile_h) $(objfiles_h) $(completer_h) $(value_h) \
  	$(gdb_string_h) $(gdbcore_h) $(gdb_stat_h) $(xcoffsolib_h)
*************** inftarg.o: inftarg.c $(defs_h) $(frame_h
*** 1809,1814 ****
--- 1811,1818 ----
  	$(gdbcore_h) $(command_h) $(gdb_stat_h) $(gdb_wait_h)
  infttrace.o: infttrace.c $(defs_h) $(frame_h) $(inferior_h) $(target_h) \
  	$(gdb_string_h) $(gdb_wait_h) $(command_h) $(gdbcore_h)
+ interps.o: interps.c $(defs_h) $(gdbcmd_h) $(ui_out_h) $(event_loop_h) \
+ 	$(event_top_h) $(interps_h) $(gdb_h) $(wrapper_h) $(gdb_events_h)
  irix4-nat.o: irix4-nat.c $(defs_h) $(inferior_h) $(gdbcore_h) $(regcache_h) \
  	$(gregset_h)
  irix5-nat.o: irix5-nat.c $(defs_h) $(inferior_h) $(gdbcore_h) $(target_h) \
*************** cli-dump.o: $(srcdir)/cli/cli-dump.c $(d
*** 2324,2329 ****
--- 2328,2336 ----
  	$(cli_decode_h) $(cli_cmds_h) $(value_h) $(completer_h) \
  	$(cli_dump_h) $(gdb_assert_h) $(target_h)
  	$(CC) -c $(INTERNAL_CFLAGS) $(srcdir)/cli/cli-dump.c
+ cli-interp.o: $(srcdir)/cli/cli-interp.c $(defs_h) $(value_h) \
+ 	$(wrapper_h) $(event_top_h) $(ui_out_h) $(cli_out_h)
+ 	$(CC) -c $(INTERNAL_CFLAGS) $(srcdir)/cli/cli-interp.c
  cli-script.o: $(srcdir)/cli/cli-script.c $(defs_h) $(value_h) $(language_h) \
  	$(ui_out_h) $(gdb_string_h) $(top_h) $(cli_cmds_h) $(cli_decode_h) \
  	$(cli_script_h)
*************** mi-cmds.o: $(srcdir)/mi/mi-cmds.c $(defs
*** 2441,2449 ****
--- 2448,2463 ----
  mi-console.o: $(srcdir)/mi/mi-console.c $(defs_h) $(mi_console_h) \
  	$(gdb_string_h)
  	$(CC) -c $(INTERNAL_CFLAGS) $(srcdir)/mi/mi-console.c
+ mi-events.o: $(srcdir)/mi/mi-events.c $(defs_h) $(ui_out_h) $(interps_h) \
+ 	$(gdb_h) $(breakpoint_h) $(mi_h)
+ 	$(CC) -c $(INTERNAL_CFLAGS) $(srcdir)/mi/mi-events.c
  mi-getopt.o: $(srcdir)/mi/mi-getopt.c $(defs_h) $(mi_getopt_h) \
  	$(gdb_string_h)
  	$(CC) -c $(INTERNAL_CFLAGS) $(srcdir)/mi/mi-getopt.c
+ mi-interp.o: $(srcdir)/mi/mi-interp.c $(defs_h) $(interps_h) \
+ 	$(event_top_h) $(event_loop_h) $(inferior_h) $(ui_out_h) \
+ 	$(top_h) $(mi_h) $(mi_cmds_h) $(mi_out_h) $(mi_console_h)
+ 	$(CC) -c $(INTERNAL_CFLAGS) $(srcdir)/mi/mi-interp.c
  mi-main.o: $(srcdir)/mi/mi-main.c $(defs_h) $(target_h) $(inferior_h) \
  	$(gdb_string_h) $(top_h) $(gdbthread_h) $(mi_cmds_h) $(mi_parse_h) \
  	$(mi_getopt_h) $(mi_console_h) $(ui_out_h) $(mi_out_h) \
Index: cli-out.c
===================================================================
RCS file: /cvs/src/src/gdb/cli-out.c,v
retrieving revision 1.14
diff -p -r1.14 cli-out.c
*** cli-out.c	19 Mar 2002 02:51:04 -0000	1.14
--- cli-out.c	23 Sep 2002 19:37:36 -0000
*************** cli_out_new (struct ui_file *stream)
*** 365,370 ****
--- 365,379 ----
    return ui_out_new (&cli_ui_out_impl, data, flags);
  }
  
+ struct ui_file *
+ cli_out_set_stream (struct ui_out *uiout, struct ui_file *stream)
+ {
+   struct ui_out_data *data = ui_out_data (uiout);
+   struct ui_file *old = data->stream;
+   data->stream = stream;
+   return old;
+ }
+ 
  /* standard gdb initialization hook */
  void
  _initialize_cli_out (void)
Index: cli-out.h
===================================================================
RCS file: /cvs/src/src/gdb/cli-out.h,v
retrieving revision 1.2
diff -p -r1.2 cli-out.h
*** cli-out.h	6 Mar 2001 08:21:06 -0000	1.2
--- cli-out.h	23 Sep 2002 19:37:36 -0000
***************
*** 23,27 ****
  #define CLI_OUT_H
  
  extern struct ui_out *cli_out_new (struct ui_file *stream);
! 
  #endif
--- 23,28 ----
  #define CLI_OUT_H
  
  extern struct ui_out *cli_out_new (struct ui_file *stream);
! extern struct ui_file *cli_out_set_stream (struct ui_out *uiout,
! 					   struct ui_file *stream);
  #endif
Index: event-loop.c
===================================================================
RCS file: /cvs/src/src/gdb/event-loop.c,v
retrieving revision 1.19
diff -p -r1.19 event-loop.c
*** event-loop.c	10 Sep 2002 19:53:24 -0000	1.19
--- event-loop.c	23 Sep 2002 19:37:37 -0000
***************
*** 22,27 ****
--- 22,28 ----
  #include "defs.h"
  #include "event-loop.h"
  #include "event-top.h"
+ #include "interps.h"
  
  #ifdef HAVE_POLL
  #if defined (HAVE_POLL_H)
*************** static void create_file_handler (int fd,
*** 210,215 ****
--- 211,217 ----
  static void invoke_async_signal_handler (void);
  static void handle_file_event (int event_file_desc);
  static int gdb_wait_for_event (void);
+ static int gdb_do_one_event (void *data);
  static int check_async_ready (void);
  static void async_queue_event (gdb_event * event_ptr, queue_position position);
  static gdb_event *create_file_event (int fd);
*************** process_event (void)
*** 345,351 ****
     can happen if there are no event sources to wait for).  If an error
     occurs catch_errors() which calls this function returns zero. */
  
! int
  gdb_do_one_event (void *data)
  {
    /* Any events already waiting in the queue? */
--- 347,353 ----
     can happen if there are no event sources to wait for).  If an error
     occurs catch_errors() which calls this function returns zero. */
  
! static int
  gdb_do_one_event (void *data)
  {
    /* Any events already waiting in the queue? */
*************** start_event_loop (void)
*** 392,401 ****
       longer any event sources registered. */
    while (1)
      {
!       int result = catch_errors (gdb_do_one_event, 0, "", RETURN_MASK_ALL);
!       if (result < 0)
  	break;
!       if (result == 0)
  	{
  	  /* FIXME: this should really be a call to a hook that is
  	     interface specific, because interfaces can display the
--- 394,416 ----
       longer any event sources registered. */
    while (1)
      {
!       int gdb_result, interp_result;
! 
!       gdb_result = catch_errors (gdb_do_one_event, 0, "", RETURN_MASK_ALL);
!       if (gdb_result < 0)
  	break;
! 
!       interp_result = catch_errors (interpreter_do_one_event, 0, "", RETURN_MASK_ALL);
!       if (interp_result < 0)
!         {
!           /* FIXME - kill the interpreter */
!         }
! 
!       /* If we long-jumped out of do_one_event, we probably
!          didn't get around to resetting the prompt, which leaves
!          readline in a messed-up state. Reset it here. */
! 
!       if (gdb_result == 0)
  	{
  	  /* FIXME: this should really be a call to a hook that is
  	     interface specific, because interfaces can display the
Index: event-top.c
===================================================================
RCS file: /cvs/src/src/gdb/event-top.c,v
retrieving revision 1.22
diff -p -r1.22 event-top.c
*** event-top.c	3 Jul 2002 20:27:12 -0000	1.22
--- event-top.c	23 Sep 2002 19:37:37 -0000
***************
*** 26,31 ****
--- 26,32 ----
  #include "terminal.h"		/* for job_control */
  #include "event-loop.h"
  #include "event-top.h"
+ #include "interps.h"
  #include <signal.h>
  
  /* For dont_repeat() */
*************** display_gdb_prompt (char *new_prompt)
*** 252,258 ****
  
    /* When an alternative interpreter has been installed, do not
       display the comand prompt. */
!   if (interpreter_p)
      return;
  
    if (target_executing && sync_execution)
--- 253,259 ----
  
    /* When an alternative interpreter has been installed, do not
       display the comand prompt. */
!   if (gdb_interpreter_display_prompt (new_prompt))
      return;
  
    if (target_executing && sync_execution)
*************** set_async_prompt (char *args, int from_t
*** 1113,1126 ****
    PROMPT (0) = savestring (new_async_prompt, strlen (new_async_prompt));
  }
  
  /* Set things up for readline to be invoked via the alternate
     interface, i.e. via a callback function (rl_callback_read_char),
     and hook up instream to the event loop. */
  void
! _initialize_event_loop (void)
  {
    if (event_loop_p)
      {
        /* If the input stream is connected to a terminal, turn on
           editing.  */
        if (ISATTY (instream))
--- 1114,1144 ----
    PROMPT (0) = savestring (new_async_prompt, strlen (new_async_prompt));
  }
  
+ void
+ _initialize_event_loop (void)
+ {
+   /* Tell gdb to use the cli_command_loop as the main loop. */
+   if (event_loop_p && command_loop_hook == NULL)
+     command_loop_hook = cli_command_loop;
+ }
+ 
  /* Set things up for readline to be invoked via the alternate
     interface, i.e. via a callback function (rl_callback_read_char),
     and hook up instream to the event loop. */
  void
! gdb_setup_readline (void)
  {
+   /* This function is a noop for the async case.  The assumption is that
+      the async setup is ALL done in gdb_init, and we would only mess it up
+      here.  The async stuff should really go away over time. */
+ 
    if (event_loop_p)
      {
+       gdb_stdout = stdio_fileopen (stdout);
+       gdb_stderr = stdio_fileopen (stderr);
+       gdb_stdlog = gdb_stderr;  /* for moment */
+       gdb_stdtarg = gdb_stderr; /* for moment */
+ 
        /* If the input stream is connected to a terminal, turn on
           editing.  */
        if (ISATTY (instream))
*************** _initialize_event_loop (void)
*** 1153,1161 ****
           register it with the event loop. */
        input_fd = fileno (instream);
  
-       /* Tell gdb to use the cli_command_loop as the main loop. */
-       command_loop_hook = cli_command_loop;
- 
        /* Now we need to create the event sources for the input file
           descriptor. */
        /* At this point in time, this is the only event source that we
--- 1171,1176 ----
*************** _initialize_event_loop (void)
*** 1166,1168 ****
--- 1181,1211 ----
        add_file_handler (input_fd, stdin_event_handler, 0);
      }
  }
+ 
+ /* Disable command input through the standard CLI channels.  Used in
+    the suspend proc for interpreters that use the standard gdb readline
+    interface, like the cli & the mi. */
+ 
+ void
+ gdb_disable_readline (void)
+ {
+   if (event_loop_p)
+     {
+       /* FIXME - It is too heavyweight to delete and remake these
+          every time you run an interpreter that needs readline.
+          It is probably better to have the interpreters cache these,
+          which in turn means that this needs to be moved into interpreter
+          specific code. */
+ 
+ #if 0
+       ui_file_delete (gdb_stdout);
+       ui_file_delete (gdb_stderr);
+       gdb_stdlog = NULL;
+       gdb_stdtarg = NULL;
+ #endif
+ 
+       rl_callback_handler_remove ();
+       delete_file_handler (input_fd);
+     }
+ }
+ 
Index: event-top.h
===================================================================
RCS file: /cvs/src/src/gdb/event-top.h,v
retrieving revision 1.4
diff -p -r1.4 event-top.h
*** event-top.h	27 Nov 2001 04:15:09 -0000	1.4
--- event-top.h	23 Sep 2002 19:37:37 -0000
*************** struct prompts
*** 71,76 ****
--- 71,78 ----
     FIXME: these should really go into top.h.  */
  
  extern void display_gdb_prompt (char *new_prompt);
+ extern void gdb_setup_readline (void);
+ extern void gdb_disable_readline (void);
  extern void async_init_signals (void);
  extern void set_async_editing_command (char *args, int from_tty,
  				       struct cmd_list_element *c);
Index: interps.c
===================================================================
RCS file: interps.c
diff -N interps.c
*** interps.c	1 Jan 1970 00:00:00 -0000
--- interps.c	23 Sep 2002 19:37:37 -0000
***************
*** 0 ****
--- 1,661 ----
+ /* Manages interpreters for gdb.
+    Copyright 2000, 2002 Free Software Foundation, Inc.
+    Written by Jim Ingham <jingham@apple.com> of Apple Computer, Inc.
+ 
+    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., 59 Temple Place - Suite 330,
+    Boston, MA 02111-1307, USA. */
+ 
+ /* This is just a first cut at separating out the "interpreter" functions
+    of gdb into self-contained modules.  There are a couple of open areas that
+    need to be sorted out:
+ 
+    1) The interpreter explicitly contains a UI_OUT, and can insert itself
+    into the event loop, but it doesn't explicitly contain hooks for readline.
+    I did this because it seems to me many interpreters won't want to use
+    the readline command interface, and it is probably simpler to just let
+    them take over the input in their resume proc.  
+ 
+    2) The event loop insertion is probably wrong.  I just inserted a 
+    do_one_event alongside gdb's do_one_event.  This probably will lead
+    to one or the other event loop getting starved.  It would be better
+    to provide conversion functions for the gdb file handlers, and when
+    an interpreter starts up, it grabs all the gdb created file handlers
+    and inserts them into its select.  This is more complicated, however,
+    and I have run out of time for now.
+ */
+ 
+ #include "defs.h"
+ #include "gdbcmd.h"
+ #include "ui-out.h"
+ #include "event-loop.h"
+ #include "event-top.h"
+ #include "interps.h"
+ #include "completer.h"
+ #include "gdb_string.h"
+ #include "gdb-events.h"
+ 
+ struct gdb_interpreter
+ {
+   char *name;			/* This is the name in "-i=" and set interpreter. */
+   struct gdb_interpreter *next;	/* Interpreters are stored in a linked list, 
+ 				   this is the next one... */
+   void *data;			/* This is a cookie that the instance of the 
+ 				   interpreter can use, for instance to call 
+ 				   itself in hook functions */
+   int inited;			/* Has the init_proc been run? */
+   struct ui_out *interpreter_out;	/* This is the ui_out used to collect 
+ 					   results for this interpreter.  It can 
+ 					   be a formatter for stdout, as is the 
+ 					   case for the console & mi outputs, or it 
+ 					   might be a result formatter. */
+   struct gdb_interpreter_procs procs;
+   int quiet_p;
+ };
+ 
+ /* Functions local to this file. */
+ static void initialize_interps (void);
+ 
+ static void set_interpreter_cmd (char *args, int from_tty,
+ 				 struct cmd_list_element *c);
+ static void list_interpreter_cmd (char *args, int from_tty);
+ static void do_set_interpreter (int not_an_fd);
+ static char **interpreter_completer (char *text, char *word);
+ 
+ /* The magic initialization routine for this module. */
+ 
+ void _initialize_interpreter (void);
+ 
+ /* Variables local to this file: */
+ 
+ static struct gdb_interpreter *interp_list = NULL;
+ static struct gdb_interpreter *current_interpreter = NULL;
+ 
+ static int interpreter_initialized = 0;
+ 
+ /* gdb_new_interpreter - This allocates space for a new interpreter,
+    fills the fields from the inputs, and returns a pointer to the
+    interpreter. */
+ 
+ struct gdb_interpreter *
+ gdb_new_interpreter (char *name,
+ 		     void *data,
+ 		     struct ui_out *uiout,
+ 		     struct gdb_interpreter_procs *procs)
+ {
+   struct gdb_interpreter *new_interp;
+ 
+   new_interp =
+     (struct gdb_interpreter *) xmalloc (sizeof (struct gdb_interpreter));
+ 
+   new_interp->name = xstrdup (name);
+   new_interp->data = data;
+   new_interp->interpreter_out = uiout;
+   new_interp->quiet_p = 0;
+   new_interp->procs.init_proc = procs->init_proc;
+   new_interp->procs.resume_proc = procs->resume_proc;
+   new_interp->procs.do_one_event_proc = procs->do_one_event_proc;
+   new_interp->procs.suspend_proc = procs->suspend_proc;
+   new_interp->procs.delete_proc = procs->delete_proc;
+   new_interp->procs.exec_proc = procs->exec_proc;
+   new_interp->procs.prompt_proc = procs->prompt_proc;
+   new_interp->inited = 0;
+ 
+   return new_interp;
+ }
+ 
+ /* Add interpreter INTERP to the gdb interpreter list.  If an
+    interpreter of the same name is already on the list, then
+    the new one is NOT added, and the function returns 0.  Otherwise
+    it returns 1. */
+ 
+ int
+ gdb_add_interpreter (struct gdb_interpreter *interp)
+ {
+   if (!interpreter_initialized)
+     initialize_interps ();
+ 
+   if (gdb_lookup_interpreter (interp->name) != NULL)
+     return 0;
+ 
+   interp->next = interp_list;
+   interp_list = interp;
+ 
+   return 1;
+ }
+ 
+ /* Looks for the interpreter INTERP in the interpreter list.  If it exists,
+    runs the delete_proc, and if this is successful, the INTERP is deleted from
+    the interpreter list and the function returns 1.  If the delete_proc fails, the
+    function returns -1 and the interpreter is NOT removed from the list.  If the
+    interp is not found, 0 is returned. */
+ 
+ int
+ gdb_delete_interpreter (struct gdb_interpreter *interp)
+ {
+   struct gdb_interpreter *cur_ptr, *prev_ptr;
+ 
+   if (!interpreter_initialized)
+     {
+       ui_out_message (uiout, 0,
+ 		      "You can't delete an interp before you have added one!");
+       return -1;
+     }
+ 
+   if (interp_list == NULL)
+     {
+       ui_out_message (uiout, 0, "No interpreters to delete.");
+       return -1;
+     }
+ 
+   if (interp_list->next == NULL)
+     {
+       ui_out_message (uiout, 0, "You can't delete gdb's only intepreter.");
+       return -1;
+     }
+ 
+   for (cur_ptr = interp_list, prev_ptr = NULL;
+        cur_ptr != NULL; prev_ptr = cur_ptr, cur_ptr = cur_ptr->next)
+     {
+       if (cur_ptr == interp)
+ 	{
+ 	  /* Can't currently delete the console interpreter... */
+ 	  if (strcmp (interp->name, "console") == 0)
+ 	    {
+ 	      ui_out_message (uiout, 0,
+ 			      "You can't delete the console interpreter.");
+ 	      return -1;
+ 	    }
+ 
+ 	  /* If the interpreter is the current interpreter, switch
+ 	     back to the console interpreter */
+ 
+ 	  if (interp == current_interpreter)
+ 	    {
+ 	      gdb_set_interpreter (gdb_lookup_interpreter ("console"));
+ 	    }
+ 
+ 	  /* Don't delete the interpreter if its delete proc fails */
+ 
+ 	  if ((interp->procs.delete_proc != NULL)
+ 	      && (!interp->procs.delete_proc (interp->data)))
+ 	    return -1;
+ 
+ 	  if (cur_ptr == interp_list)
+ 	    interp_list = cur_ptr->next;
+ 	  else
+ 	    prev_ptr->next = cur_ptr->next;
+ 
+ 	  break;
+ 	}
+     }
+ 
+   if (cur_ptr == NULL)
+     return 0;
+   else
+     return 1;
+ }
+ 
+ /* This sets the current interpreter to be INTERP.  If INTERP has not
+    been initialized, then this will also run the init proc.  If the
+    init proc is successful, return 1, if it fails, set the old
+    interpreter back in place and return 0.  If we can't restore the
+    old interpreter, then raise an internal error, since we are in
+    pretty bad shape at this point. */
+ 
+ int
+ gdb_set_interpreter (struct gdb_interpreter *interp)
+ {
+   struct gdb_interpreter *old_interp = current_interpreter;
+   int first_time = 0;
+ 
+ 
+   char buffer[64];
+ 
+   if (current_interpreter != NULL)
+     {
+       do_all_continuations ();
+       ui_out_flush (uiout);
+       if (current_interpreter->procs.suspend_proc
+ 	  && !current_interpreter->procs.suspend_proc (current_interpreter->
+ 						       data))
+ 	{
+ 	  error ("Could not suspend interpreter \"%s\"\n",
+ 		 current_interpreter->name);
+ 	}
+     }
+   else
+     {
+       first_time = 1;
+     }
+ 
+   current_interpreter = interp;
+ 
+   /* We use interpreter_p for the "set interpreter" variable, so we need
+      to make sure we have a malloc'ed copy for the set command to free. */
+   if (interpreter_p != NULL
+       && strcmp (current_interpreter->name, interpreter_p) != 0)
+     {
+       xfree (interpreter_p);
+ 
+       interpreter_p = xstrdup (current_interpreter->name);
+     }
+ 
+   uiout = interp->interpreter_out;
+ 
+   /* Run the init proc.  If it fails, try to restore the old interp. */
+ 
+   if (!interp->inited)
+     {
+       if (interp->procs.init_proc != NULL)
+ 	{
+ 	  if (!interp->procs.init_proc (interp->data))
+ 	    {
+ 	      if (!gdb_set_interpreter (old_interp))
+ 		internal_error (__FILE__, __LINE__,
+ 				"Failed to initialize new interp \"%s\" %s",
+ 				interp->name,
+ 				"and could not restore old interp!\n");
+ 	      return 0;
+ 	    }
+ 	  else
+ 	    {
+ 	      interp->inited = 1;
+ 	    }
+ 	}
+       else
+ 	{
+ 	  interp->inited = 1;
+ 	}
+     }
+ 
+   /* Clear out any installed interpreter hooks/event handlers. */
+   clear_interpreter_hooks ();
+ 
+   if (interp->procs.resume_proc != NULL
+       && (!interp->procs.resume_proc (interp->data)))
+     {
+       if (!gdb_set_interpreter (old_interp))
+ 	internal_error (__FILE__, __LINE__,
+ 			"Failed to initialize new interp \"%s\" %s",
+ 			interp->name, "and could not restore old interp!\n");
+       return 0;
+     }
+ 
+   /* Finally, put up the new prompt to show that we are indeed here. 
+      Also, display_gdb_prompt for the console does some readline magic
+      which is needed for the console interpreter, at least... */
+ 
+   if (!first_time)
+     {
+       if (!gdb_interpreter_is_quiet (interp))
+ 	{
+ 	  sprintf (buffer, "Switching to interpreter \"%.24s\".\n",
+ 		   interp->name);
+ 	  ui_out_text (uiout, buffer);
+ 	}
+       display_gdb_prompt (NULL);
+     }
+ 
+   return 1;
+ }
+ 
+ /*
+  * gdb_lookup_interpreter - Looks up the interpreter for NAME.  If
+  * no such interpreter exists, return NULL, otherwise return a pointer
+  * to the interpreter. 
+  */
+ 
+ struct gdb_interpreter *
+ gdb_lookup_interpreter (char *name)
+ {
+   struct gdb_interpreter *interp;
+ 
+   if (name == NULL || strlen (name) == 0)
+     return NULL;
+ 
+   for (interp = interp_list; interp != NULL; interp = interp->next)
+     {
+       if (strcmp (interp->name, name) == 0)
+ 	return interp;
+     }
+ 
+   return NULL;
+ }
+ 
+ /* Returns the current interpreter. */
+ 
+ struct gdb_interpreter *
+ gdb_current_interpreter ()
+ {
+   return current_interpreter;
+ }
+ 
+ struct ui_out *
+ gdb_interpreter_ui_out (struct gdb_interpreter *interp)
+ {
+   if (interp != NULL)
+     return interp->interpreter_out;
+ 
+   return current_interpreter->interpreter_out;
+ }
+ 
+ /* Returns true if the current interp is the passed in name. */
+ int
+ gdb_current_interpreter_is_named (char *interp_name)
+ {
+   struct gdb_interpreter *current_interp = gdb_current_interpreter ();
+ 
+   if (current_interp)
+     return (strcmp (current_interp->name, interp_name) == 0);
+ 
+   return 0;
+ }
+ 
+ /* This is called in display_gdb_prompt.
+    If the current interpreter defines a prompt_proc, then that proc is 
+    run.  If the proc returns a non-zero value, display_gdb_prompt will
+    return without itself displaying the prompt. */
+ 
+ int
+ gdb_interpreter_display_prompt (char *new_prompt)
+ {
+   if (current_interpreter->procs.prompt_proc == NULL)
+     return 0;
+   else
+     return current_interpreter->procs.prompt_proc (current_interpreter->data,
+ 						   new_prompt);
+ }
+ 
+ int
+ gdb_interpreter_is_quiet (struct gdb_interpreter *interp)
+ {
+   if (interp != NULL)
+     return interp->quiet_p;
+   else
+     return current_interpreter->quiet_p;
+ }
+ 
+ int
+ gdb_interpreter_set_quiet (struct gdb_interpreter *interp, int quiet)
+ {
+   int old_val = interp->quiet_p;
+   interp->quiet_p = quiet;
+   return old_val;
+ }
+ 
+ /* gdb_interpreter_exec - This executes COMMAND_STR in the current 
+    interpreter. */
+ 
+ int
+ gdb_interpreter_exec (char *command_str)
+ {
+   if (current_interpreter->procs.exec_proc != NULL)
+     {
+       return current_interpreter->procs.exec_proc (current_interpreter->data,
+ 						   command_str);
+     }
+ 
+   return 0;
+ }
+ 
+ struct gdb_interpreter_procs *
+ gdb_interpreter_get_procs (struct gdb_interpreter *interp)
+ {
+   if (interp != NULL)
+     return &interp->procs;
+ 
+   return &current_interpreter->procs;
+ }
+ 
+ void *
+ gdb_interpreter_get_data (struct gdb_interpreter *interp)
+ {
+   if (interp != NULL)
+     return interp->data;
+ 
+   return current_interpreter->data;
+ }
+ 
+ int
+ interpreter_do_one_event ()
+ {
+   if (current_interpreter->procs.do_one_event_proc == NULL)
+     return 0;
+ 
+   return current_interpreter->procs.do_one_event_proc (current_interpreter->
+ 						       data);
+ }
+ 
+ /* A convenience routine that nulls out all the
+    common command hooks.  Use it when removing your interpreter in its 
+    suspend proc. */
+ 
+ void
+ clear_interpreter_hooks ()
+ {
+   init_ui_hook = 0;
+   print_frame_info_listing_hook = 0;
+   /*print_frame_more_info_hook = 0; */
+   query_hook = 0;
+   warning_hook = 0;
+   create_breakpoint_hook = 0;
+   delete_breakpoint_hook = 0;
+   modify_breakpoint_hook = 0;
+   interactive_hook = 0;
+   registers_changed_hook = 0;
+   readline_begin_hook = 0;
+   readline_hook = 0;
+   readline_end_hook = 0;
+   register_changed_hook = 0;
+   memory_changed_hook = 0;
+   context_hook = 0;
+   target_wait_hook = 0;
+   call_command_hook = 0;
+   error_hook = 0;
+   error_begin_hook = 0;
+   command_loop_hook = 0;
+   clear_gdb_event_hooks ();
+ }
+ 
+ /* This is a lazy init routine, called the first time
+    the interpreter module is used.  I put it here just in case, but I haven't
+    thought of a use for it yet.  I will probably bag it soon, since I don't
+    think it will be necessary. */
+ 
+ static void
+ initialize_interps (void)
+ {
+   interpreter_initialized = 1;
+   /* Don't know if anything needs to be done here... */
+ }
+ 
+ /* set_interpreter_cmd - This implements "set interpreter foo". */
+ 
+ static void
+ set_interpreter_cmd (char *args, int from_tty, struct cmd_list_element *c)
+ {
+   struct gdb_interpreter *interp_ptr;
+ 
+   dont_repeat ();
+ 
+   if (cmd_type (c) != set_cmd)
+     return;
+ 
+   interp_ptr = gdb_lookup_interpreter (interpreter_p);
+   if (interp_ptr != NULL)
+     {
+       if (!gdb_set_interpreter (interp_ptr))
+ 	error ("\nCould not switch to interpreter \"%s\", %s%s\".\n",
+ 	       interp_ptr->name, "reverting to interpreter \"",
+ 	       current_interpreter->name);
+     }
+   else
+     {
+       char *bad_name = interpreter_p;
+       interpreter_p = xstrdup (current_interpreter->name);
+       error ("Could not find interpreter \"%s\".", bad_name);
+     }
+ }
+ 
+ /* list_interpreter_cmd - This implements "info interpreters". */
+ 
+ void
+ list_interpreter_cmd (char *args, int from_tty)
+ {
+   struct gdb_interpreter *interp_ptr;
+ 
+   ui_out_list_begin (uiout, "interpreters");
+   for (interp_ptr = interp_list; interp_ptr != NULL;
+        interp_ptr = interp_ptr->next)
+     {
+       ui_out_text (uiout, "  * ");
+       ui_out_field_string (uiout, "interpreter", interp_ptr->name);
+       ui_out_text (uiout, "\n");
+     }
+   ui_out_list_end (uiout);
+ }
+ 
+ void
+ interpreter_exec_cmd (char *args, int from_tty)
+ {
+   struct gdb_interpreter *old_interp, *interp_to_use;
+   char **prules = NULL;
+   char **trule = NULL;
+   unsigned int nrules;
+   unsigned int i;
+   int old_quiet, use_quiet;
+ 
+   prules = buildargv (args);
+   if (prules == NULL)
+     {
+       error ("unable to parse arguments");
+     }
+ 
+   nrules = 0;
+   if (prules != NULL)
+     {
+       for (trule = prules; *trule != NULL; trule++)
+ 	{
+ 	  nrules++;
+ 	}
+     }
+ 
+   if (nrules < 2)
+     error ("usage: interpreter-exec <interpreter> [ <command> ... ]");
+ 
+   old_interp = gdb_current_interpreter ();
+ 
+   interp_to_use = gdb_lookup_interpreter (prules[0]);
+   if (interp_to_use == NULL)
+     error ("Could not find interpreter \"%s\".", prules[0]);
+ 
+   /* Temporarily set interpreters quiet */
+   old_quiet = gdb_interpreter_set_quiet (old_interp, 1);
+   use_quiet = gdb_interpreter_set_quiet (interp_to_use, 1);
+ 
+   if (!gdb_set_interpreter (interp_to_use))
+     error ("Could not switch to interpreter \"%s\".", prules[0]);
+ 
+   for (i = 1; i < nrules; i++)
+     {
+       if (!gdb_interpreter_exec (prules[i]))
+ 	{
+ 	  gdb_set_interpreter (old_interp);
+ 	  gdb_interpreter_set_quiet (interp_to_use, old_quiet);
+ 	  error
+ 	    ("interpreter-exec: mi_interpreter_execute: error in command: \"%s\".",
+ 	     prules[i]);
+ 	  break;
+ 	}
+     }
+ 
+   gdb_set_interpreter (old_interp);
+   gdb_interpreter_set_quiet (interp_to_use, use_quiet);
+   gdb_interpreter_set_quiet (old_interp, old_quiet);
+ }
+ 
+ /* List the possible interpreters which could complete the given text. */
+ 
+ static char **
+ interpreter_completer (char *text, char *word)
+ {
+   int alloced, textlen;
+   int num_matches;
+   char **matches;
+   struct gdb_interpreter *interp;
+ 
+   /* We expect only a very limited number of interpreters, so just
+      allocate room for all of them. */
+   for (interp = interp_list; interp != NULL; interp = interp->next)
+     ++alloced;
+   matches = (char **) xmalloc (alloced * sizeof (char *));
+ 
+   num_matches = 0;
+   textlen = strlen (text);
+   for (interp = interp_list; interp != NULL; interp = interp->next)
+     {
+       if (strncmp (interp->name, text, textlen) == 0)
+ 	{
+ 	  matches[num_matches] =
+ 	    (char *) xmalloc (strlen (word) + strlen (interp->name) + 1);
+ 	  if (word == text)
+ 	    strcpy (matches[num_matches], interp->name);
+ 	  else if (word > text)
+ 	    {
+ 	      /* Return some portion of interp->name */
+ 	      strcpy (matches[num_matches], interp->name + (word - text));
+ 	    }
+ 	  else
+ 	    {
+ 	      /* Return some of text plus interp->name */
+ 	      strncpy (matches[num_matches], word, text - word);
+ 	      matches[num_matches][text - word] = '\0';
+ 	      strcat (matches[num_matches], interp->name);
+ 	    }
+ 	  ++num_matches;
+ 	}
+     }
+ 
+   if (num_matches == 0)
+     {
+       xfree (matches);
+       matches = NULL;
+     }
+   else if (num_matches < alloced)
+     {
+       matches = (char **) xrealloc ((char *) matches, ((num_matches + 1)
+ 						       * sizeof (char *)));
+       matches[num_matches] = NULL;
+     }
+ 
+   return matches;
+ }
+ 
+ /* This just adds the "set interpreter" and "info interpreters" commands. */
+ 
+ void
+ _initialize_interpreter (void)
+ {
+   struct cmd_list_element *c;
+ 
+   c = add_cmd ("interpreter-exec", class_support,
+ 	       interpreter_exec_cmd,
+ 	       "Execute a command in an interpreter.  It takes two arguments:\n\
+ The first argument is the name of the interpreter to use.\n\
+ The second argument is the command to execute.\n", &cmdlist);
+   set_cmd_completer (c, interpreter_completer);
+ }
Index: interps.h
===================================================================
RCS file: interps.h
diff -N interps.h
*** interps.h	1 Jan 1970 00:00:00 -0000
--- interps.h	23 Sep 2002 19:37:37 -0000
***************
*** 0 ****
--- 1,76 ----
+ /* Manages interpreters for gdb.
+    Copyright 2000,2002 Free Software Foundation, Inc.
+    Written by Jim Ingham <jingham@apple.com> of Apple Computer, Inc.
+ 
+    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., 59 Temple Place - Suite 330,
+    Boston, MA 02111-1307, USA. */
+ 
+ #ifndef GDB_INTERPRETER_H
+ #define GDB_INTERPRETER_H
+ 
+ typedef int (*interp_init_ftype) (void *data);
+ typedef int (*interp_resume_ftype) (void *data);
+ typedef int (*interp_do_one_event_ftype) (void *data);
+ typedef int (*interp_suspend_ftype) (void *data);
+ typedef int (*interp_delete_ftype) (void *data);
+ typedef int (*interp_prompt_ftype) (void *data, char *new_prompt);
+ typedef int (*interp_exec_ftype) (void *data, char *command);
+ 
+ struct ui_out;
+ struct gdb_interpreter;
+ 
+ struct gdb_interpreter_procs
+ {
+   interp_init_ftype init_proc;
+   interp_resume_ftype resume_proc;
+   interp_do_one_event_ftype do_one_event_proc;
+   interp_suspend_ftype suspend_proc;
+   interp_delete_ftype delete_proc;
+   interp_exec_ftype exec_proc;
+   interp_prompt_ftype prompt_proc;
+ };
+ 
+ extern struct gdb_interpreter
+   *gdb_new_interpreter (char *name, void *data, struct ui_out *uiout,
+ 			struct gdb_interpreter_procs *procs);
+ 
+ extern int gdb_add_interpreter (struct gdb_interpreter *interp);
+ extern int gdb_delete_interpreter (struct gdb_interpreter *interp);
+ extern int gdb_set_interpreter (struct gdb_interpreter *interp);
+ extern struct gdb_interpreter *gdb_lookup_interpreter (char *name);
+ extern struct gdb_interpreter *gdb_current_interpreter ();
+ extern struct ui_out *gdb_interpreter_ui_out (struct gdb_interpreter *interp);
+ extern int gdb_current_interpreter_is_named (char *interp_name);
+ extern int gdb_interpreter_exec (char *command_str);
+ extern int gdb_interpreter_display_prompt (char *new_prompt);
+ extern int gdb_interpreter_set_quiet (struct gdb_interpreter *interp,
+ 				      int quiet);
+ extern int gdb_interpreter_is_quiet (struct gdb_interpreter *interp);
+ extern struct gdb_interpreter_procs *gdb_interpreter_get_procs (struct
+ 								gdb_interpreter
+ 								*interp);
+ extern void *gdb_interpreter_get_data (struct gdb_interpreter *interp);
+ extern int interpreter_do_one_event ();
+ 
+ void clear_interpreter_hooks ();
+ 
+ /* well-known interpreters */
+ #define GDB_INTERPRETER_CONSOLE		"console"
+ #define GDB_INTERPRETER_MI0		"mi0"
+ #define GDB_INTERPRETER_MI1             "mi1"
+ #define GDB_INTERPRETER_MI		"mi"
+ #endif /* GDB_INTERPRETER_H */
Index: top.c
===================================================================
RCS file: /cvs/src/src/gdb/top.c,v
retrieving revision 1.67
diff -p -r1.67 top.c
*** top.c	9 Sep 2002 21:03:26 -0000	1.67
--- top.c	23 Sep 2002 19:37:37 -0000
***************
*** 63,68 ****
--- 63,69 ----
  #include <ctype.h>
  #include "ui-out.h"
  #include "cli-out.h"
+ #include "interps.h"
  
  /* Default command line prompt.  This is overriden in some configs. */
  
*************** gdb_init (char *argv0)
*** 2126,2142 ****
      init_ui_hook (argv0);
  
    /* Install the default UI */
!   if (!init_ui_hook)
!     {
!       uiout = cli_out_new (gdb_stdout);
  
!       /* All the interpreters should have had a look at things by now.
! 	 Initialize the selected interpreter. */
!       if (interpreter_p)
! 	{
! 	  fprintf_unfiltered (gdb_stderr, "Interpreter `%s' unrecognized.\n",
! 			      interpreter_p);
! 	  exit (1);
! 	}
!     }
  }
--- 2127,2152 ----
      init_ui_hook (argv0);
  
    /* Install the default UI */
!   /* All the interpreters should have had a look at things by now.
!      Initialize the selected interpreter. */
!   {
!     struct gdb_interpreter *interp;
!     if (interpreter_p == NULL)
!       interpreter_p = xstrdup (GDB_INTERPRETER_CONSOLE);
  
!     interp = gdb_lookup_interpreter (interpreter_p);
! 
!     if (interp == NULL)
!       {
!         fprintf_unfiltered (gdb_stderr, "Interpreter `%s' unrecognized.\n",
!                             interpreter_p);
!         exit (1);
!       }
!     if (!gdb_set_interpreter (interp))
!       {
!         fprintf_unfiltered (gdb_stderr, "Interpreter `%s' failed to initialize.\n",
!                             interpreter_p);
!         exit (1);
!       }
!   }
  }
Index: wrapper.c
===================================================================
RCS file: /cvs/src/src/gdb/wrapper.c,v
retrieving revision 1.14
diff -p -r1.14 wrapper.c
*** wrapper.c	31 Oct 2001 03:16:04 -0000	1.14
--- wrapper.c	23 Sep 2002 19:37:38 -0000
***************
*** 19,24 ****
--- 19,25 ----
  #include "defs.h"
  #include "value.h"
  #include "wrapper.h"
+ #include "top.h"		/* for execute_command */
  
  /* Use this struct to pass arguments to wrapper routines. We assume
     (arbitrarily) that no gdb function takes more than ten arguments. */
*************** struct captured_value_struct_elt_args
*** 51,56 ****
--- 52,63 ----
    struct value **result_ptr;
  };
  
+ struct captured_execute_command_args
+ {
+   char *command;
+   int from_tty;
+ };
+ 
  static int wrap_parse_exp_1 (char *);
  
  static int wrap_evaluate_expression (char *);
*************** do_captured_value_struct_elt (struct ui_
*** 331,333 ****
--- 338,357 ----
    return GDB_RC_OK;
  }
  
+ static int
+ do_captured_execute_command (struct ui_out *uiout, void *data)
+ {
+   struct captured_execute_command_args *args = data;
+   execute_command (args->command, args->from_tty);
+   return GDB_RC_OK;
+ }
+ 
+ enum gdb_rc
+ gdb_execute_command (struct ui_out *uiout, char *command, int from_tty)
+ {
+   struct captured_execute_command_args args;
+   args.command = command;
+   args.from_tty = from_tty;
+   return catch_exceptions (uiout, do_captured_execute_command, &args,
+ 			   NULL, RETURN_MASK_ALL);
+ }
Index: wrapper.h
===================================================================
RCS file: /cvs/src/src/gdb/wrapper.h,v
retrieving revision 1.12
diff -p -r1.12 wrapper.h
*** wrapper.h	31 Oct 2001 03:16:04 -0000	1.12
--- wrapper.h	23 Sep 2002 19:37:38 -0000
***************
*** 21,26 ****
--- 21,30 ----
  #include "gdb.h"
  
  struct value;
+ struct block;
+ struct expression;
+ struct ui_out;
+ struct type;
  
  /* Use this struct to pass arguments to wrapper routines. */
  struct gdb_wrapper_arguments;
*************** extern int gdb_value_ind (struct value *
*** 46,49 ****
--- 50,55 ----
  
  extern int gdb_parse_and_eval_type (char *, int, struct type **);
  
+ extern enum gdb_rc gdb_execute_command (struct ui_out *uiout, char *command,
+ 					int from_tty);
  #endif /* WRAPPER_H */
Index: cli/cli-interp.c
===================================================================
RCS file: cli/cli-interp.c
diff -N cli/cli-interp.c
*** cli/cli-interp.c	1 Jan 1970 00:00:00 -0000
--- cli/cli-interp.c	23 Sep 2002 19:37:38 -0000
***************
*** 0 ****
--- 1,127 ----
+ /* CLI Definitions for GDB
+    Copyright 2002 Free Software Foundation, Inc.
+ 
+    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., 59 Temple Place - Suite 330,
+    Boston, MA 02111-1307, USA.  */
+ 
+ #include "defs.h"
+ #include "interps.h"
+ #include "wrapper.h"
+ #include "event-top.h"
+ #include "ui-out.h"
+ #include "cli-out.h"
+ 
+ /* Prototypes for the CLI Interpreter functions */
+ 
+ int cli_interpreter_init (void *data);
+ int cli_interpreter_resume (void *data);
+ int cli_interpreter_do_one_event (void *data);
+ int cli_interpreter_suspend (void *data);
+ int cli_interpreter_delete (void *data);
+ int cli_interpreter_exec (void *data, char *command_str);
+ int cli_interpreter_display_prompt (void *data, char *new_prompt);
+ 
+ /* These are the ui_out and the interpreter for the console interpreter. */
+ static struct ui_out *cli_uiout;
+ static struct gdb_interpreter *cli_interp;
+ 
+ /* These implement the cli out interpreter: */
+ 
+ int
+ cli_interpreter_init (void *data)
+ {
+   return 1;
+ }
+ 
+ int
+ cli_interpreter_resume (void *data)
+ {
+   /*sync_execution = 1;*/
+   gdb_setup_readline ();
+   return 1;
+ }
+ 
+ int
+ cli_interpreter_do_one_event (void *data)
+ {
+   return 1;
+ }
+ 
+ int
+ cli_interpreter_suspend (void *data)
+ {
+   gdb_disable_readline ();
+   return 1;
+ }
+ 
+ int
+ cli_interpreter_delete (void *data)
+ {
+   return 1;
+ }
+ 
+ int
+ cli_interpreter_display_prompt (void *data, char *new_prompt)
+ {
+   if (gdb_interpreter_is_quiet (NULL))
+     {
+       return 1;
+     }
+   else
+     {
+       return 0;
+     }
+ }
+ 
+ int
+ cli_interpreter_exec (void *data, char *command_str)
+ {
+   int result;
+   struct ui_file *old_stream;
+ 
+   /* gdb_stdout could change between the time cli_uiout was initialized
+      and now. Since we're probably using a different interpreter which has
+      a new ui_file for gdb_stdout, use that one instead of the default.
+   
+      It is important that it gets reset everytime, since the user could
+      set gdb to use a different interpreter. */
+   old_stream = cli_out_set_stream (cli_uiout, gdb_stdout);
+   result = gdb_execute_command (cli_uiout, command_str, 1);
+   cli_out_set_stream (cli_uiout, old_stream);
+   return result;
+ }
+ 
+ /* standard gdb initialization hook */
+ void
+ _initialize_cli_interp (void)
+ {
+   struct gdb_interpreter_procs procs = {
+     cli_interpreter_init,	/* init_proc */
+     cli_interpreter_resume,	/* resume_proc */
+     cli_interpreter_do_one_event, /* do_one_event_proc */
+     cli_interpreter_suspend,	/* suspend_proc */
+     cli_interpreter_delete,	/* delete_proc */
+     cli_interpreter_exec,	/* exec_proc */
+     cli_interpreter_display_prompt /* prompt_proc */
+   };
+ 
+   /* Create a default uiout builder for the CLI. */
+   cli_uiout = cli_out_new (gdb_stdout);
+   cli_interp = gdb_new_interpreter (GDB_INTERPRETER_CONSOLE, NULL, cli_uiout,
+ 				    &procs);
+   gdb_add_interpreter (cli_interp);
+ }
Index: mi/mi-cmds.c
===================================================================
RCS file: /cvs/src/src/gdb/mi/mi-cmds.c,v
retrieving revision 1.8
diff -p -r1.8 mi-cmds.c
*** mi/mi-cmds.c	6 Mar 2001 08:21:45 -0000	1.8
--- mi/mi-cmds.c	23 Sep 2002 19:37:38 -0000
*************** struct mi_cmd mi_cmds[] =
*** 88,93 ****
--- 88,94 ----
    {"gdb-show", "show %s", 0},
    {"gdb-source", 0, 0},
    {"gdb-version", "show version", 0},
+   {"interpreter-exec", 0, 0, mi_cmd_interpreter_exec},
    {"kod-info", 0, 0},
    {"kod-list", 0, 0},
    {"kod-list-object-types", 0, 0},
Index: mi/mi-cmds.h
===================================================================
RCS file: /cvs/src/src/gdb/mi/mi-cmds.h,v
retrieving revision 1.5
diff -p -r1.5 mi-cmds.h
*** mi/mi-cmds.h	6 Mar 2001 08:21:45 -0000	1.5
--- mi/mi-cmds.h	23 Sep 2002 19:37:38 -0000
*************** extern mi_cmd_args_ftype mi_cmd_exec_ste
*** 75,80 ****
--- 75,81 ----
  extern mi_cmd_args_ftype mi_cmd_exec_until;
  extern mi_cmd_args_ftype mi_cmd_exec_interrupt;
  extern mi_cmd_argv_ftype mi_cmd_gdb_exit;
+ extern mi_cmd_argv_ftype mi_cmd_interpreter_exec;
  extern mi_cmd_argv_ftype mi_cmd_stack_info_depth;
  extern mi_cmd_argv_ftype mi_cmd_stack_list_args;
  extern mi_cmd_argv_ftype mi_cmd_stack_list_frames;
*************** extern int mi_debug_p;
*** 122,125 ****
--- 123,129 ----
  /* Raw console output - FIXME: should this be a parameter? */
  extern struct ui_file *raw_stdout;
  
+ extern char *mi_error_message;
+ extern void mi_error_last_message (void);
+ extern void mi_execute_command (char *cmd, int from_tty);
  #endif
Index: mi/mi-console.c
===================================================================
RCS file: /cvs/src/src/gdb/mi/mi-console.c,v
retrieving revision 1.8
diff -p -r1.8 mi-console.c
*** mi/mi-console.c	19 Mar 2002 02:51:08 -0000	1.8
--- mi/mi-console.c	23 Sep 2002 19:37:38 -0000
*************** struct mi_console_file
*** 37,49 ****
      struct ui_file *raw;
      struct ui_file *buffer;
      const char *prefix;
    };
  
  int mi_console_file_magic;
  
  struct ui_file *
  mi_console_file_new (struct ui_file *raw,
! 		     const char *prefix)
  {
    struct ui_file *ui_file = ui_file_new ();
    struct mi_console_file *mi_console = XMALLOC (struct mi_console_file);
--- 37,50 ----
      struct ui_file *raw;
      struct ui_file *buffer;
      const char *prefix;
+     char quote;
    };
  
  int mi_console_file_magic;
  
  struct ui_file *
  mi_console_file_new (struct ui_file *raw,
! 		     const char *prefix, char quote)
  {
    struct ui_file *ui_file = ui_file_new ();
    struct mi_console_file *mi_console = XMALLOC (struct mi_console_file);
*************** mi_console_file_new (struct ui_file *raw
*** 51,56 ****
--- 52,58 ----
    mi_console->raw = raw;
    mi_console->buffer = mem_fileopen ();
    mi_console->prefix = prefix;
+   mi_console->quote = quote;
    set_ui_file_fputs (ui_file, mi_console_file_fputs);
    set_ui_file_flush (ui_file, mi_console_file_flush);
    set_ui_file_data (ui_file, mi_console, mi_console_file_delete);
*************** mi_console_raw_packet (void *data,
*** 96,104 ****
    if (length_buf > 0)
      {
        fputs_unfiltered (mi_console->prefix, mi_console->raw);
!       fputs_unfiltered ("\"", mi_console->raw);
!       fputstrn_unfiltered (buf, length_buf, '"', mi_console->raw);
!       fputs_unfiltered ("\"\n", mi_console->raw);
        gdb_flush (mi_console->raw);
      }
  }
--- 98,114 ----
    if (length_buf > 0)
      {
        fputs_unfiltered (mi_console->prefix, mi_console->raw);
!       if (mi_console->quote)
! 	{
! 	  fputs_unfiltered ("\"", mi_console->raw);
! 	  fputstrn_unfiltered (buf, length_buf, mi_console->quote, mi_console->raw);
! 	  fputs_unfiltered ("\"\n", mi_console->raw);
! 	}
!       else
! 	{
! 	  fputstrn_unfiltered (buf, length_buf, 0, mi_console->raw);
! 	  fputs_unfiltered ("\n", mi_console->raw);
! 	}
        gdb_flush (mi_console->raw);
      }
  }
Index: mi/mi-console.h
===================================================================
RCS file: /cvs/src/src/gdb/mi/mi-console.h,v
retrieving revision 1.4
diff -p -r1.4 mi-console.h
*** mi/mi-console.h	6 Mar 2001 08:21:45 -0000	1.4
--- mi/mi-console.h	23 Sep 2002 19:37:38 -0000
***************
*** 22,27 ****
  #ifndef MI_CONSOLE_H
  #define MI_CONSOLE_H
  
! extern struct ui_file *mi_console_file_new (struct ui_file *raw, const char *prefix);
  
  #endif
--- 22,28 ----
  #ifndef MI_CONSOLE_H
  #define MI_CONSOLE_H
  
! extern struct ui_file *mi_console_file_new (struct ui_file *raw, const char *prefix,
! 					    char quote);
  
  #endif
Index: mi/mi-events.c
===================================================================
RCS file: mi/mi-events.c
diff -N mi/mi-events.c
*** mi/mi-events.c	1 Jan 1970 00:00:00 -0000
--- mi/mi-events.c	23 Sep 2002 19:37:38 -0000
***************
*** 0 ****
--- 1,120 ----
+ /* MI Event Handlers
+    Copyright 2002 Free Software Foundation, Inc.
+ 
+    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., 59 Temple Place - Suite 330,
+    Boston, MA 02111-1307, USA.  */
+ 
+ #include "defs.h"
+ #include "ui-out.h"
+ #include "interps.h"
+ #include "gdb.h"
+ #include "breakpoint.h"
+ 
+ #include "mi.h"
+ 
+ void 
+ mi_interp_stack_changed_hook (void)
+ {
+   struct ui_out *saved_ui_out = uiout;
+   struct mi_out *tmp_mi_out;
+ 
+   if (gdb_current_interpreter_is_named (GDB_INTERPRETER_MI0))
+     uiout = gdb_interpreter_ui_out (mi0_interp);
+   else
+     uiout = gdb_interpreter_ui_out (mi_interp);
+ 
+   ui_out_list_begin (uiout, "MI_HOOK_RESULT");
+   ui_out_field_string (uiout, "HOOK_TYPE", "stack_changed");
+   ui_out_list_end (uiout);
+   uiout = saved_ui_out;
+ }
+ 
+ static void
+ event_notify (const char *string, ...)
+ {
+   va_list args;
+ 
+   if (!gdb_current_interpreter_is_named (GDB_INTERPRETER_MI0)
+       && !gdb_current_interpreter_is_named (GDB_INTERPRETER_MI1))
+     {
+       va_start (args, string);
+       vfprintf_unfiltered (mi_event_channel, string, args);
+       va_end (args);
+       gdb_flush (mi_event_channel);
+     }
+ }
+ 
+ /* breakpoint-create,number=bpnum */
+ void
+ mi_create_breakpoint (int bpnum)
+ {
+   event_notify ("breakpoint-create,number=\"%d\"", bpnum);
+ }
+ 
+ void
+ mi_modify_breakpoint (int bpnum)
+ {
+   event_notify ("breakpoint-modify,number=\"%d\"", bpnum);
+ }
+ 
+ void
+ mi_delete_breakpoint (int bpnum)
+ {
+   event_notify ("breakpoint-delete,number=\"%d\"", bpnum);
+ }
+ 
+ void
+ mi_create_tracepoint (int tpnum)
+ {
+   event_notify ("tracepoint-create,number=\"%d\"", tpnum);
+ }
+ 
+ void
+ mi_modify_tracepoint (int tpnum)
+ {
+   event_notify ("tracepoint-modify,number=\"%d\"", tpnum);
+ }
+ 
+ void
+ mi_delete_tracepoint (int tpnum)
+ {
+   event_notify ("tracepoint-delete,number=\"%d\"", tpnum);
+ }
+ 
+ void
+ mi_architecture_changed (void)
+ {
+   event_notify ("architecture-changed");
+ }
+ 
+ void
+ mi_target_changed (void)
+ {
+   event_notify ("target-changed");
+ }
+ 
+ void
+ mi_selected_frame_level_changed (int level)
+ {
+   event_notify ("selected-frame-level-changed,level=\"%d\"", level);
+ }
+ 
+ void
+ mi_context_changed (int thread_id)
+ {
+   event_notify ("context-changed,thread=\"%d\"", thread_id);
+ }
Index: mi/mi-interp.c
===================================================================
RCS file: mi/mi-interp.c
diff -N mi/mi-interp.c
*** mi/mi-interp.c	1 Jan 1970 00:00:00 -0000
--- mi/mi-interp.c	23 Sep 2002 19:37:38 -0000
***************
*** 0 ****
--- 1,477 ----
+ /* MI Interpreter Definitions and Commands
+    Copyright 2002 Free Software Foundation, Inc.
+ 
+    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., 59 Temple Place - Suite 330,
+    Boston, MA 02111-1307, USA.  */
+ 
+ #include "defs.h"
+ #include "interps.h"
+ #include "event-top.h"
+ #include "event-loop.h"
+ #include "inferior.h"
+ #include "ui-out.h"
+ #include "top.h"
+ 
+ #include "mi.h"
+ #include "mi-cmds.h"
+ #include "mi-out.h"
+ #include "mi-console.h"
+ 
+ /* MI's output channels */
+ struct ui_file *mi_stdout;
+ struct ui_file *mi_stderr;
+ struct ui_file *mi_stdlog;
+ struct ui_file *mi_stdtarg;
+ struct ui_file *mi_event_channel;
+ 
+ /* This is the interpreter for the mi... */
+ struct gdb_interpreter *mi0_interp;
+ struct gdb_interpreter *mi1_interp;
+ struct gdb_interpreter *mi_interp;
+ 
+ /* These are the interpreter setup, etc. functions for the MI interpreter */
+ static int mi_interpreter_init (void *data);
+ static int mi_interpreter_resume (void *data);
+ static int mi_interpreter_do_one_event (void *data);
+ static int mi_interpreter_suspend (void *data);
+ static int mi_interpreter_delete (void *data);
+ static int mi_interpreter_exec (void *data, char *command);
+ static int mi_interpreter_prompt (void *data, char *new_prompt);
+ 
+ static void mi_execute_command_wrapper (char *cmd);
+ static void mi_command_loop (int mi_version);
+ static char *mi_input (char *);
+ 
+ /* These are hooks that we put in place while doing interpreter_exec
+    so we can report interesting things that happened "behind the mi's
+    back" in this command */
+ static int mi_interp_query_hook (const char *ctlstr, va_list ap);
+ static char *mi_interp_read_one_line_hook (char *prompt, int repeat,
+ 					   char *anno);
+ 
+ static void mi0_command_loop (void);
+ static void mi1_command_loop (void);
+ 
+ static void mi_insert_notify_hooks (void);
+ static void mi_remove_notify_hooks (void);
+ 
+ static struct gdb_events mi_event_handlers =
+   {
+     mi_create_breakpoint,
+     mi_delete_breakpoint,
+     mi_modify_breakpoint,
+     mi_create_tracepoint,
+     mi_delete_tracepoint,
+     mi_modify_tracepoint,
+     mi_architecture_changed,
+     mi_target_changed,
+     mi_selected_frame_level_changed
+   };
+ 
+ static int
+ mi_interpreter_init (void *data)
+ {
+   static struct gdb_events handlers;
+ 
+   /* Why is this a part of the mi architecture? */
+ 
+   mi_setup_architecture_data ();
+ 
+   /* HACK: We need to force stdout/stderr to point at the console.  This avoids
+      any potential side effects caused by legacy code that is still
+      using the TUI / fputs_unfiltered_hook.  So we set up output channels for
+      this now, and swap them in when we are run. */
+ 
+   raw_stdout = stdio_fileopen (stdout);
+ 
+   /* Create MI channels */
+   mi_stdout = mi_console_file_new (raw_stdout, "~", '"');
+   mi_stderr = mi_console_file_new (raw_stdout, "&", '"');
+   mi_stdlog = mi_stderr;
+   mi_stdtarg = mi_console_file_new (raw_stdout, "@", '"');
+   mi_event_channel = mi_console_file_new (raw_stdout, "=", 0);
+ 
+   return 1;
+ }
+ 
+ static int
+ mi_interpreter_resume (void *data)
+ {
+   /* As per hack note in mi_interpreter_init, swap in the output channels... */
+ 
+   gdb_setup_readline ();
+   mi_register_gdbarch_swap ();
+ 
+   if (event_loop_p)
+     {
+       /* These overwrite some of the initialization done in
+          _intialize_event_loop. */
+       call_readline = gdb_readline2;
+       input_handler = mi_execute_command_wrapper;
+       add_file_handler (input_fd, stdin_event_handler, 0);
+       async_command_editing_p = 0;
+       /* FIXME: This is a total hack for now.  PB's use of the MI implicitly
+          relies on a bug in the async support which allows asynchronous
+          commands to leak through the commmand loop.  The bug involves
+          (but is not limited to) the fact that sync_execution was
+          erroneously initialized to 0.  Duplicate by initializing it
+          thus here... */
+       sync_execution = 0;
+     }
+ 
+   gdb_stdout = mi_stdout;
+   /* Route error and log output through the MI */
+   gdb_stderr = mi_stderr;
+   gdb_stdlog = mi_stdlog;
+   /* Route target output through the MI. */
+   gdb_stdtarg = mi_stdtarg;
+ 
+   /* Replace all the hooks that we know about.  There really needs to be a better way
+      of doing this... */
+   clear_interpreter_hooks ();
+   set_gdb_event_hooks (&mi_event_handlers);
+ 
+   show_load_progress = mi_load_progress;
+ 
+   /* If we're _the_ interpreter, take control. */
+   if (gdb_current_interpreter_is_named (GDB_INTERPRETER_MI0))
+     command_loop_hook = mi0_command_loop;
+   else if (gdb_current_interpreter_is_named (GDB_INTERPRETER_MI1))
+     command_loop_hook = mi1_command_loop;
+   else if (gdb_current_interpreter_is_named (GDB_INTERPRETER_MI))
+     command_loop_hook = mi1_command_loop;
+   else
+     return 0;
+ 
+   return 1;
+ }
+ 
+ static int
+ mi_interpreter_suspend (void *data)
+ {
+   gdb_disable_readline ();
+   return 1;
+ }
+ 
+ static int
+ mi_interpreter_delete (void *data)
+ {
+   return 1;
+ }
+ 
+ static int
+ mi_interpreter_exec (void *data, char *command)
+ {
+   mi_execute_command_wrapper (command);
+   return 1;
+ }
+ 
+ static int
+ mi_interpreter_prompt (void *data, char *new_prompt)
+ {
+   return 1;
+ }
+ 
+ static int
+ mi_do_one_event (void *data)
+ {
+   return 1;
+ }
+ 
+ static void
+ mi_interpreter_exec_continuation (struct continuation_arg *arg)
+ {
+   bpstat_do_actions (&stop_bpstat);
+   if (!target_executing)
+     {
+       fputs_unfiltered ("*stopped", raw_stdout);
+       mi_out_put (uiout, raw_stdout);
+       fputs_unfiltered ("\n", raw_stdout);
+       fputs_unfiltered ("(gdb) \n", raw_stdout);
+       gdb_flush (raw_stdout);
+       do_exec_cleanups (ALL_CLEANUPS);
+     }
+   else if (target_can_async_p ())
+     {
+       add_continuation (mi_interpreter_exec_continuation, NULL);
+     }
+ }
+ 
+ enum mi_cmd_result
+ mi_cmd_interpreter_exec (char *command, char **argv, int argc)
+ {
+   struct gdb_interpreter *interp_to_use;
+   enum mi_cmd_result result = MI_CMD_DONE;
+   int i;
+   struct gdb_interpreter_procs *procs;
+ 
+   if (argc < 2)
+     {
+       xasprintf (&mi_error_message,
+ 		 "mi_cmd_interpreter_exec: Usage: -interpreter-exec interp command");
+       return MI_CMD_ERROR;
+     }
+ 
+   interp_to_use = gdb_lookup_interpreter (argv[0]);
+   if (interp_to_use == NULL)
+     {
+       xasprintf (&mi_error_message,
+ 		 "mi_cmd_interpreter_exec: could not find interpreter \"%s\"",
+ 		 argv[0]);
+       return MI_CMD_ERROR;
+     }
+ 
+   procs = gdb_interpreter_get_procs (interp_to_use);
+   if (!procs->exec_proc)
+     {
+       xasprintf (&mi_error_message,
+ 		 "mi_cmd_interpreter_exec: interpreter \"%s\" does not support command execution",
+ 		 argv[0]);
+       return MI_CMD_ERROR;
+     }
+ 
+   /* Insert the MI out hooks, making sure to also call the interpreter's hooks
+      if it has any. */
+   /* KRS: We shouldn't need this... Events should be installed and they should
+      just ALWAYS fire something out down the MI channel... */
+   mi_insert_notify_hooks ();
+ 
+   /* Now run the code... */
+ 
+   for (i = 1; i < argc; i++)
+     {
+       char *buff = NULL;
+       /* Do this in a cleaner way...  We want to force execution to be
+          asynchronous for commands that run the target.  */
+       if (target_can_async_p () && (strcmp (argv[0], "console") == 0))
+ 	{
+ 	  int len = strlen (argv[i]);
+ 	  buff = xmalloc (len + 2);
+ 	  memcpy (buff, argv[i], len);
+ 	  buff[len] = '&';
+ 	  buff[len + 1] = '\0';
+ 	}
+ 
+       /* We had to set sync_execution = 0 for the mi (well really for Project
+          Builder's use of the mi - particularly so interrupting would work.
+          But for console commands to work, we need to initialize it to 1 -
+          since that is what the cli expects - before running the command,
+          and then set it back to 0 when we are done. */
+       sync_execution = 1;
+       if (procs->exec_proc (gdb_interpreter_get_data (interp_to_use), argv[i]) < 0)
+ 	{
+ 	  mi_error_last_message ();
+ 	  result = MI_CMD_ERROR;
+ 	  break;
+ 	}
+       xfree (buff);
+       do_exec_error_cleanups (ALL_CLEANUPS);
+       sync_execution = 0;
+     }
+ 
+   mi_remove_notify_hooks ();
+ 
+   /* Okay, now let's see if the command set the inferior going...
+      Tricky point - have to do this AFTER resetting the interpreter, since
+      changing the interpreter will clear out all the continuations for
+      that interpreter... */
+ 
+   if (target_can_async_p () && target_executing)
+     {
+       fputs_unfiltered ("^running\n", raw_stdout);
+       add_continuation (mi_interpreter_exec_continuation, NULL);
+     }
+ 
+   return result;
+ }
+ 
+ /*
+  * mi_insert_notify_hooks - This inserts a number of hooks that are meant to produce
+  * async-notify ("=") MI messages while running commands in another interpreter
+  * using mi_interpreter_exec.  The canonical use for this is to allow access to
+  * the gdb CLI interpreter from within the MI, while still producing MI style output
+  * when actions in the CLI command change gdb's state.
+ */
+ 
+ static void
+ mi_insert_notify_hooks (void)
+ {
+   query_hook = mi_interp_query_hook;
+ }
+ 
+ static void
+ mi_remove_notify_hooks ()
+ {
+   query_hook = NULL;
+ }
+ 
+ static int
+ mi_interp_query_hook (const char *ctlstr, va_list ap)
+ {
+   return 1;
+ }
+ 
+ static char *
+ mi_interp_read_one_line_hook (char *prompt, int repeat, char *anno)
+ {
+   static char buff[256];
+   printf_unfiltered ("=read-one-line,prompt=\"%s\"\n", prompt);
+   gdb_flush (gdb_stdout);
+   (void) fgets (buff, sizeof (buff), stdin);
+   buff[(strlen (buff) - 1)] = 0;
+   return buff;
+ }
+ 
+ static void
+ output_control_change_notification (char *notification)
+ {
+   printf_unfiltered ("^");
+   printf_unfiltered ("%s\n", notification);
+   gdb_flush (gdb_stdout);
+ }
+ 
+ static void
+ mi_execute_command_wrapper (char *cmd)
+ {
+   mi_execute_command (cmd, stdin == instream);
+ }
+ 
+ static void
+ mi0_command_loop (void)
+ {
+   mi_command_loop (0);
+ }
+ 
+ static void
+ mi1_command_loop (void)
+ {
+   mi_command_loop (1);
+ }
+ 
+ static void
+ mi_command_loop (int mi_version)
+ {
+ #if 0
+   /* HACK: Force stdout/stderr to point at the console.  This avoids
+      any potential side effects caused by legacy code that is still
+      using the TUI / fputs_unfiltered_hook */
+   raw_stdout = stdio_fileopen (stdout);
+   /* Route normal output through the MIx */
+   gdb_stdout = mi_console_file_new (raw_stdout, "~", '"');
+   /* Route error and log output through the MI */
+   gdb_stderr = mi_console_file_new (raw_stdout, "&", '"');
+   gdb_stdlog = gdb_stderr;
+   /* Route target output through the MI. */
+   gdb_stdtarg = mi_console_file_new (raw_stdout, "@", '"');
+   /* HACK: Poke the ui_out table directly.  Should we be creating a
+      mi_out object wired up to the above gdb_stdout / gdb_stderr? */
+   uiout = mi_out_new (mi_version);
+   /* HACK: Override any other interpreter hooks.  We need to create a
+      real event table and pass in that. */
+   init_ui_hook = 0;
+   /* command_loop_hook = 0; */
+   print_frame_info_listing_hook = 0;
+   query_hook = 0;
+   warning_hook = 0;
+   create_breakpoint_hook = 0;
+   delete_breakpoint_hook = 0;
+   modify_breakpoint_hook = 0;
+   interactive_hook = 0;
+   registers_changed_hook = 0;
+   readline_begin_hook = 0;
+   readline_hook = 0;
+   readline_end_hook = 0;
+   register_changed_hook = 0;
+   memory_changed_hook = 0;
+   context_hook = 0;
+   target_wait_hook = 0;
+   call_command_hook = 0;
+   error_hook = 0;
+   error_begin_hook = 0;
+   show_load_progress = mi_load_progress;
+ #endif
+   /* Turn off 8 bit strings in quoted output.  Any character with the
+      high bit set is printed using C's octal format. */
+   sevenbit_strings = 1;
+   /* Tell the world that we're alive */
+   fputs_unfiltered ("(gdb) \n", raw_stdout);
+   gdb_flush (raw_stdout);
+   if (!event_loop_p)
+     simplified_command_loop (mi_input, mi_execute_command);
+   else
+     start_event_loop ();
+ }
+ 
+ static char *
+ mi_input (char *buf)
+ {
+   return gdb_readline (NULL);
+ }
+ 
+ void
+ _initialize_mi_interp (void)
+ {
+   struct gdb_interpreter_procs procs =
+     {
+       mi_interpreter_init,	/* init_proc */
+       mi_interpreter_resume,	/* resume_proc */
+       NULL,			/* do_one_event_proc */
+       mi_interpreter_suspend,	/* suspend_proc */
+       mi_interpreter_delete,	/* delete_proc */
+       mi_interpreter_exec,	/* exec_proc */
+       mi_interpreter_prompt	/* prompt_proc */
+     };
+ 
+   /* Create MI0 interpreter */
+   if (mi0_interp == NULL)
+     {
+       mi0_interp =
+ 	gdb_new_interpreter (GDB_INTERPRETER_MI0, NULL, mi_out_new (0),
+ 			     &procs);
+       if (mi0_interp == NULL)
+ 	error
+ 	  ("Couldn't allocate a new interpreter for the mi0 interpreter\n");
+       if (gdb_add_interpreter (mi0_interp) != 1)
+ 	error ("Couldn't add the mi0 interpreter to gdb.\n");
+     }
+ 
+   /* Create MI1 interpreter */
+   if (mi1_interp == NULL)
+     {
+       mi1_interp =
+ 	gdb_new_interpreter (GDB_INTERPRETER_MI1, NULL, mi_out_new (1),
+ 			     &procs);
+       if (mi1_interp == NULL)
+ 	error
+ 	  ("Couldn't allocate a new interpreter for the mi1 interpreter\n");
+       if (gdb_add_interpreter (mi1_interp) != 1)
+ 	error ("Couldn't add the mi1 interpreter to gdb.\n");
+     }
+ 
+   /* Create MI2 interpreter */
+   if (mi_interp == NULL)
+     {
+       mi_interp =
+ 	gdb_new_interpreter (GDB_INTERPRETER_MI, NULL, mi_out_new (2),
+ 			     &procs);
+       if (mi_interp == NULL)
+ 	error
+ 	  ("Couldn't allocate a new interpreter for the mi interpreter\n");
+       if (gdb_add_interpreter (mi_interp) != 1)
+ 	error ("Couldn't add the mi interpreter to gdb.\n");
+     }
+ }
Index: mi/mi-main.c
===================================================================
RCS file: /cvs/src/src/gdb/mi/mi-main.c,v
retrieving revision 1.31
diff -p -r1.31 mi-main.c
*** mi/mi-main.c	11 Sep 2002 21:49:04 -0000	1.31
--- mi/mi-main.c	23 Sep 2002 19:37:38 -0000
***************
*** 33,38 ****
--- 33,39 ----
  #include "mi-console.h"
  #include "ui-out.h"
  #include "mi-out.h"
+ #include "interps.h"
  #include "event-loop.h"
  #include "event-top.h"
  #include "gdbcore.h"		/* for write_memory() */
*************** struct ui_file *raw_stdout;
*** 77,103 ****
  /* The token of the last asynchronous command */
  static char *last_async_command;
  static char *previous_async_command;
! static char *mi_error_message;
  static char *old_regs;
  
  extern void _initialize_mi_main (void);
! static char *mi_input (char *);
! static void mi_execute_command (char *cmd, int from_tty);
  static enum mi_cmd_result mi_cmd_execute (struct mi_parse *parse);
  
  static void mi_execute_cli_command (const char *cli, char *args);
  static enum mi_cmd_result mi_execute_async_cli_command (char *mi, char *args, int from_tty);
- static void mi_execute_command_wrapper (char *cmd);
  
  void mi_exec_async_cli_cmd_continuation (struct continuation_arg *arg);
  
  static int register_changed_p (int regnum);
  static int get_register (int regnum, int format);
! static void mi_load_progress (const char *section_name,
! 			      unsigned long sent_so_far,
! 			      unsigned long total_section,
! 			      unsigned long total_sent,
! 			      unsigned long grand_total);
  
  /* FIXME: these should go in some .h file, but infcmd.c doesn't have a
     corresponding .h file. These wrappers will be obsolete anyway, once
--- 78,102 ----
  /* The token of the last asynchronous command */
  static char *last_async_command;
  static char *previous_async_command;
! char *mi_error_message;
  static char *old_regs;
  
  extern void _initialize_mi_main (void);
! void mi_execute_command (char *cmd, int from_tty);
  static enum mi_cmd_result mi_cmd_execute (struct mi_parse *parse);
  
  static void mi_execute_cli_command (const char *cli, char *args);
  static enum mi_cmd_result mi_execute_async_cli_command (char *mi, char *args, int from_tty);
  
  void mi_exec_async_cli_cmd_continuation (struct continuation_arg *arg);
  
  static int register_changed_p (int regnum);
  static int get_register (int regnum, int format);
! void mi_load_progress (const char *section_name,
! 		       unsigned long sent_so_far,
! 		       unsigned long total_section,
! 		       unsigned long total_sent,
! 		       unsigned long grand_total);
  
  /* FIXME: these should go in some .h file, but infcmd.c doesn't have a
     corresponding .h file. These wrappers will be obsolete anyway, once
*************** static void mi_load_progress (const char
*** 105,110 ****
--- 104,118 ----
  extern void interrupt_target_command_wrapper (char *, int);
  extern void return_command_wrapper (char *, int);
  
+ /* A helper function which will set mi_error_message to error_last_message. */
+ void
+ mi_error_last_message (void)
+ {
+   char *s = error_last_message ();
+   xasprintf (&mi_error_message, s);
+   xfree (s);
+ }
+ 
  /* Command implementations. FIXME: Is this libgdb? No.  This is the MI
     layer that calls libgdb.  Any operation used in the below should be
     formalized. */
*************** mi_execute_command (char *cmd, int from_
*** 1165,1171 ****
    struct mi_parse *command;
    struct captured_mi_execute_command_args args;
    struct ui_out *saved_uiout = uiout;
!   int result, rc;
  
    /* This is to handle EOF (^D). We just quit gdb. */
    /* FIXME: we should call some API function here. */
--- 1173,1179 ----
    struct mi_parse *command;
    struct captured_mi_execute_command_args args;
    struct ui_out *saved_uiout = uiout;
!   int result;
  
    /* This is to handle EOF (^D). We just quit gdb. */
    /* FIXME: we should call some API function here. */
*************** mi_cmd_execute (struct mi_parse *parse)
*** 1273,1284 ****
      }
  }
  
- static void
- mi_execute_command_wrapper (char *cmd)
- {
-   mi_execute_command (cmd, stdin == instream);
- }
- 
  /* FIXME: This is just a hack so we can get some extra commands going.
     We don't want to channel things through the CLI, but call libgdb directly */
  /* Use only for synchronous commands */
--- 1281,1286 ----
*************** mi_exec_async_cli_cmd_continuation (stru
*** 1381,1393 ****
    do_exec_cleanups (ALL_CLEANUPS);
  }
  
! static char *
! mi_input (char *buf)
! {
!   return gdb_readline (NULL);
! }
! 
! static void
  mi_load_progress (const char *section_name,
  		  unsigned long sent_so_far,
  		  unsigned long total_section,
--- 1383,1389 ----
    do_exec_cleanups (ALL_CLEANUPS);
  }
  
! void
  mi_load_progress (const char *section_name,
  		  unsigned long sent_so_far,
  		  unsigned long total_section,
*************** mi_load_progress (const char *section_na
*** 1456,1573 ****
      }
  }
  
! static void
! mi_command_loop (int mi_version)
! {
!   /* HACK: Force stdout/stderr to point at the console.  This avoids
!      any potential side effects caused by legacy code that is still
!      using the TUI / fputs_unfiltered_hook */
!   raw_stdout = stdio_fileopen (stdout);
!   /* Route normal output through the MIx */
!   gdb_stdout = mi_console_file_new (raw_stdout, "~");
!   /* Route error and log output through the MI */
!   gdb_stderr = mi_console_file_new (raw_stdout, "&");
!   gdb_stdlog = gdb_stderr;
!   /* Route target output through the MI. */
!   gdb_stdtarg = mi_console_file_new (raw_stdout, "@");
! 
!   /* HACK: Poke the ui_out table directly.  Should we be creating a
!      mi_out object wired up to the above gdb_stdout / gdb_stderr? */
!   uiout = mi_out_new (mi_version);
! 
!   /* HACK: Override any other interpreter hooks.  We need to create a
!      real event table and pass in that. */
!   init_ui_hook = 0;
!   /* command_loop_hook = 0; */
!   print_frame_info_listing_hook = 0;
!   query_hook = 0;
!   warning_hook = 0;
!   create_breakpoint_hook = 0;
!   delete_breakpoint_hook = 0;
!   modify_breakpoint_hook = 0;
!   interactive_hook = 0;
!   registers_changed_hook = 0;
!   readline_begin_hook = 0;
!   readline_hook = 0;
!   readline_end_hook = 0;
!   register_changed_hook = 0;
!   memory_changed_hook = 0;
!   context_hook = 0;
!   target_wait_hook = 0;
!   call_command_hook = 0;
!   error_hook = 0;
!   error_begin_hook = 0;
!   show_load_progress = mi_load_progress;
! 
!   /* Turn off 8 bit strings in quoted output.  Any character with the
!      high bit set is printed using C's octal format. */
!   sevenbit_strings = 1;
! 
!   /* Tell the world that we're alive */
!   fputs_unfiltered ("(gdb) \n", raw_stdout);
!   gdb_flush (raw_stdout);
! 
!   if (!event_loop_p)
!     simplified_command_loop (mi_input, mi_execute_command);
!   else
!     start_event_loop ();
! }
! 
! static void
! mi0_command_loop (void)
! {
!   mi_command_loop (0);
! }
! 
! static void
! mi1_command_loop (void)
! {
!   mi_command_loop (1);
! }
! 
! static void
! setup_architecture_data (void)
  {
    /* don't trust REGISTER_BYTES to be zero. */
    old_regs = xmalloc (REGISTER_BYTES + 1);
    memset (old_regs, 0, REGISTER_BYTES + 1);
  }
  
- static void
- mi_init_ui (char *arg0)
- {
-   /* Eventually this will contain code that takes control of the
-      console. */
- }
- 
  void
! _initialize_mi_main (void)
  {
-   if (interpreter_p == NULL)
-     return;
- 
-   /* If we're _the_ interpreter, take control. */
-   if (strcmp (interpreter_p, "mi0") == 0)
-     command_loop_hook = mi0_command_loop;
-   else if (strcmp (interpreter_p, "mi") == 0
- 	   || strcmp (interpreter_p, "mi1") == 0)
-     command_loop_hook = mi1_command_loop;
-   else
-     return;
- 
-   init_ui_hook = mi_init_ui;
-   setup_architecture_data ();
    register_gdbarch_swap (&old_regs, sizeof (old_regs), NULL);
!   register_gdbarch_swap (NULL, 0, setup_architecture_data);
!   if (event_loop_p)
!     {
!       /* These overwrite some of the initialization done in
! 	 _intialize_event_loop. */
!       call_readline = gdb_readline2;
!       input_handler = mi_execute_command_wrapper;
!       add_file_handler (input_fd, stdin_event_handler, 0);
!       async_command_editing_p = 0;
!     }
!   /* FIXME: Should we notify main that we are here as a possible
!      interpreter? */
  }
--- 1452,1468 ----
      }
  }
  
! void
! mi_setup_architecture_data (void)
  {
    /* don't trust REGISTER_BYTES to be zero. */
    old_regs = xmalloc (REGISTER_BYTES + 1);
    memset (old_regs, 0, REGISTER_BYTES + 1);
  }
  
  void
! mi_register_gdbarch_swap (void)
  {
    register_gdbarch_swap (&old_regs, sizeof (old_regs), NULL);
!   register_gdbarch_swap (NULL, 0, mi_setup_architecture_data);
  }
Index: mi/mi.h
===================================================================
RCS file: mi/mi.h
diff -N mi/mi.h
*** mi/mi.h	1 Jan 1970 00:00:00 -0000
--- mi/mi.h	23 Sep 2002 19:37:38 -0000
***************
*** 0 ****
--- 1,59 ----
+ /* MI Internal Functions
+    Copyright 2002 Free Software Foundation, Inc.
+ 
+    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., 59 Temple Place - Suite 330,
+    Boston, MA 02111-1307, USA.  */
+ 
+ #ifndef MI_H
+ #define MI_H
+ /* The mi interpreters. */
+ struct ui_file;
+ struct breakpoint;
+ struct gdb_interpreter;
+ extern struct gdb_interpreter *mi_interp;
+ extern struct gdb_interpreter *mi0_interp;
+ 
+ extern void mi_setup_architecture_data (void);
+ extern void mi_register_gdbarch_swap (void);
+ 
+ /* MI's output channels */
+ extern struct ui_file *mi_stdout;
+ extern struct ui_file *mi_stderr;
+ extern struct ui_file *mi_stdlog;
+ extern struct ui_file *mi_stdtarg;
+ extern struct ui_file *mi_event_channel;
+ 
+ /* Events/Hooks */
+ extern void mi_load_progress (const char *section_name,
+ 			      unsigned long sent_so_far,
+ 			      unsigned long total_section,
+ 			      unsigned long total_sent,
+ 			      unsigned long grand_total);
+ extern void mi_interp_frame_changed_hook (int new_frame_number);
+ extern void mi_interp_context_hook (int thread_id);
+ 
+ extern void mi_create_breakpoint (int bpnum);
+ extern void mi_modify_breakpoint (int bpnum);
+ extern void mi_delete_breakpoint (int bpnum);
+ extern void mi_create_tracepoint (int bpnum);
+ extern void mi_modify_tracepoint (int bpnum);
+ extern void mi_delete_tracepoint (int bpnum);
+ extern void mi_architecture_changed (void);
+ extern void mi_target_changed (void);
+ extern void mi_selected_frame_level_changed (int level);
+ extern void mi_context_changed (int thread_id);
+ #endif /* MI_H */

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [RFC] Interpreters (~final) (fwd)
  2002-09-23 12:44     ` Keith Seitz
@ 2002-09-30 11:35       ` Elena Zannoni
  2002-09-30 15:58       ` Elena Zannoni
  1 sibling, 0 replies; 16+ messages in thread
From: Elena Zannoni @ 2002-09-30 11:35 UTC (permalink / raw)
  To: Keith Seitz; +Cc: Elena Zannoni, gdb-patches


I am looking more at the branch than at the patch. I am trying to come
up with another way of breaking this down. If I am lucky.

A couple of little things I noticed. More in a bit.

The error messages in interps.c print strings with mi_ in them, like:

 + 	  error
 + 	    ("interpreter-exec: mi_interpreter_execute: error in command: \"%s\".",
 + 	     prules[i]);


The use of wrapper.[ch] is discouraged. Put the necessary safe
functions near where they are used (so we wack 2 files from the list
of stuff to merge). Look at corefile.c:safe_read_memory_integer, for
instance. 

Who uses gdb_delete_interpreter? If it is there "just in case" add a
comment that says so.

I bet more changes are coming down the pipe, but could we tighten the
interfaces a bit. I think some more functions could be made static and
removed from .h files.

Elena





^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [RFC] Interpreters (~final) (fwd)
  2002-09-23 12:44     ` Keith Seitz
  2002-09-30 11:35       ` Elena Zannoni
@ 2002-09-30 15:58       ` Elena Zannoni
  1 sibling, 0 replies; 16+ messages in thread
From: Elena Zannoni @ 2002-09-30 15:58 UTC (permalink / raw)
  To: Keith Seitz; +Cc: Elena Zannoni, gdb-patches


another thought.

I don't see 'info interpreter' 'set intepreter' working on the branch.

but I see the support routines.

Elena


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [RFC] Interpreters (~final) (fwd)
  2002-08-28 17:13           ` Andrew Cagney
@ 2002-08-28 22:09             ` Eli Zaretskii
  0 siblings, 0 replies; 16+ messages in thread
From: Eli Zaretskii @ 2002-08-28 22:09 UTC (permalink / raw)
  To: Andrew Cagney; +Cc: Michael Snyder, Keith Seitz, gdb-patches


On Wed, 28 Aug 2002, Andrew Cagney wrote:

> (I note the doco has been posted).

That means I missed it somehow.  Sorry about that.

(I thought Keith was saying that he didn't yet post the documentation 
patches.)


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [RFC] Interpreters (~final) (fwd)
  2002-08-28 13:33         ` Michael Snyder
@ 2002-08-28 17:13           ` Andrew Cagney
  2002-08-28 22:09             ` Eli Zaretskii
  0 siblings, 1 reply; 16+ messages in thread
From: Andrew Cagney @ 2002-08-28 17:13 UTC (permalink / raw)
  To: Michael Snyder, Keith Seitz; +Cc: Eli Zaretskii, gdb-patches

> Keith Seitz wrote:
> 
>> 
>> On Wed, 28 Aug 2002, Eli Zaretskii wrote:
>> 
> 
>> > I think this is a great feature (required also for Emacs's GUD interface
>> > to switch to MI instead of using the (deprecated) annotations).  However,
>> > I think it should be documented in the GDB manual (more accurately in
>> > gdbmi.texinfo).
> 
>> 
>> I have documentation for all the changes I've made in the interpreter
>> branch that I've been working on. I have not yet submitted them because I
>> didn't want to overload maintainers with a zillion patches.
>> 
>> If it is desired, I can post the documentation patches.
> 
> 
> This might be a good way for folks to get a handle on the work before
> reviewing it.

Yes.  The patch needs to include both the testcase and the doco changes 
(I note the doco has been posted).

Andrew



^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [RFC] Interpreters (~final) (fwd)
  2002-08-28  8:37       ` Keith Seitz
  2002-08-28  9:03         ` Eli Zaretskii
@ 2002-08-28 13:33         ` Michael Snyder
  2002-08-28 17:13           ` Andrew Cagney
  1 sibling, 1 reply; 16+ messages in thread
From: Michael Snyder @ 2002-08-28 13:33 UTC (permalink / raw)
  To: Keith Seitz; +Cc: Eli Zaretskii, gdb-patches

Keith Seitz wrote:
> 
> On Wed, 28 Aug 2002, Eli Zaretskii wrote:
> 
> > I think this is a great feature (required also for Emacs's GUD interface
> > to switch to MI instead of using the (deprecated) annotations).  However,
> > I think it should be documented in the GDB manual (more accurately in
> > gdbmi.texinfo).
> 
> I have documentation for all the changes I've made in the interpreter
> branch that I've been working on. I have not yet submitted them because I
> didn't want to overload maintainers with a zillion patches.
> 
> If it is desired, I can post the documentation patches.

This might be a good way for folks to get a handle on the work before
reviewing it.


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [RFC] Interpreters (~final) (fwd)
  2002-08-28  8:37       ` Keith Seitz
@ 2002-08-28  9:03         ` Eli Zaretskii
  2002-08-28 13:33         ` Michael Snyder
  1 sibling, 0 replies; 16+ messages in thread
From: Eli Zaretskii @ 2002-08-28  9:03 UTC (permalink / raw)
  To: keiths; +Cc: gdb-patches

> Date: Wed, 28 Aug 2002 08:12:00 -0700 (PDT)
> From: Keith Seitz <keiths@redhat.com>
> 
> I have documentation for all the changes I've made in the interpreter 
> branch that I've been working on.

Thanks.

> If it is desired, I can post the documentation patches.

I don't mind reviewing documentation patches even if the code is not
yet approved, so it's up to you.  You could post them now so that you
are ready to commit as soon as the code patches are approved, or you
could post the doco patches only then.


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [RFC] Interpreters (~final) (fwd)
  2002-08-28  7:14     ` Eli Zaretskii
@ 2002-08-28  8:37       ` Keith Seitz
  2002-08-28  9:03         ` Eli Zaretskii
  2002-08-28 13:33         ` Michael Snyder
  0 siblings, 2 replies; 16+ messages in thread
From: Keith Seitz @ 2002-08-28  8:37 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: gdb-patches

On Wed, 28 Aug 2002, Eli Zaretskii wrote:

> I think this is a great feature (required also for Emacs's GUD interface 
> to switch to MI instead of using the (deprecated) annotations).  However, 
> I think it should be documented in the GDB manual (more accurately in 
> gdbmi.texinfo).

I have documentation for all the changes I've made in the interpreter 
branch that I've been working on. I have not yet submitted them because I 
didn't want to overload maintainers with a zillion patches.

If it is desired, I can post the documentation patches.

Keith



^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [RFC] Interpreters (~final) (fwd)
  2002-08-27 15:19   ` Keith Seitz
@ 2002-08-28  7:14     ` Eli Zaretskii
  2002-08-28  8:37       ` Keith Seitz
  0 siblings, 1 reply; 16+ messages in thread
From: Eli Zaretskii @ 2002-08-28  7:14 UTC (permalink / raw)
  To: Keith Seitz; +Cc: Michael Snyder, gdb-patches


On Tue, 27 Aug 2002, Keith Seitz wrote:

> For example, on my interps branch, one can use the "interpreter-exec" 
> MI command to run a CLI command:
> 
> (gdb)
> -interpreter-exec console "break main"
> ~"Breakpoint 3 at 0x8074fc6: file ../../src/gdb/main.c, line 743.\n"
> =breakpoint-create,number="3"
> ^done
> (gdb)

I think this is a great feature (required also for Emacs's GUD interface 
to switch to MI instead of using the (deprecated) annotations).  However, 
I think it should be documented in the GDB manual (more accurately in 
gdbmi.texinfo).

Thanks!


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [RFC] Interpreters (~final) (fwd)
       [not found] <1030485672.17451.ezmlm@sources.redhat.com>
@ 2002-08-27 15:21 ` Jim Ingham
  0 siblings, 0 replies; 16+ messages in thread
From: Jim Ingham @ 2002-08-27 15:21 UTC (permalink / raw)
  To: gdb-patches

The first motivation, actually, was to separate out the MI and Console 
"interpreters" in gdb so that you can run gdb under a GUI using the MI, 
but still provide a way to run "real" console commands.  By this I mean 
that you get correct console output, the extra prompts - completion, 
command entry mode for breakpoint commands, etc and everything else you 
need to make a convincing console window within an MI driven use of 
gdb.  Project Builder provides such a console window, so I hacked this 
up for PB, and I think Eclipse wants the same thing for its debugger, 
so Keith is working on merging our patches (this latter bit is just a 
guess, he could be doing it out of the goodness of his heart...)

I started to also think about how to do the more complex job of 
providing a way to "lash another interpreter onto gdb", but I didn't 
get very far with this.  The main issue with this is how to 
intelligently share events with the gdb interpreter.  Fortunately, the 
MI and the gdb CLI share the same event sources, etc.  So this bit it 
trivial.  Something like Tcl will have its own wait loop and thus list 
of wait sources, and to get good behavior you really need to convert 
the event sources from something the CLI & MI likes to something the 
other interpreter likes.

But this second stage is not necessary for getting Console behaviors 
from the MI.  The stuff Keith extracted from our sources is sufficient 
for that.

Jim

On Tuesday, August 27, 2002, at 03:01  PM, 
gdb-patches-digest-help@sources.redhat.com wrote:

> Keith Seitz wrote:
>>
>> Ping.
>
> Hi Keith,
>
> I'm not sure whose domain this is.  /me lacks context.
> What is it we're trying to do here?  Provide replacements
> to the CLI interpreter?  Lash an extension language into gdb?
> Excuse my ignorance, I haven't followed the conversation
> too closely.
>
> Michael
>
>
--
Jim Ingham                                   jingham@apple.com
Developer Tools - gdb
Apple Computer


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [RFC] Interpreters (~final) (fwd)
  2002-08-27 15:01 ` Michael Snyder
@ 2002-08-27 15:19   ` Keith Seitz
  2002-08-28  7:14     ` Eli Zaretskii
  0 siblings, 1 reply; 16+ messages in thread
From: Keith Seitz @ 2002-08-27 15:19 UTC (permalink / raw)
  To: Michael Snyder; +Cc: gdb-patches

On Tue, 27 Aug 2002, Michael Snyder wrote:

> I'm not sure whose domain this is.  /me lacks context.
> What is it we're trying to do here?  Provide replacements
> to the CLI interpreter?  Lash an extension language into gdb?
> Excuse my ignorance, I haven't followed the conversation 
> too closely.

No problem, let me explain what this all does and where it all comes from.

Much of this code comes originally from Jim Ingham at Apple.  Like us, 
they wanted to address the lack of a command-line pass-through in MI, 
i.e., they want a console window like Insight's, one which can execute CLI 
commands in the MI interpreter.

Jim's original patch included the ability to do switch interpreters at 
runtime. I have (temporarily) removed that, so that it stays static. But 
the useful bit is that one can execute a command in another interpreter.

For example, on my interps branch, one can use the "interpreter-exec" 
MI command to run a CLI command:

(gdb)
-interpreter-exec console "break main"
~"Breakpoint 3 at 0x8074fc6: file ../../src/gdb/main.c, line 743.\n"
=breakpoint-create,number="3"
^done
(gdb)

Note that the CLI output is properly encapsulated for MI. This all mainly 
exists for MI, but it could be used, for example, by Insight, too, 
although no one has attempted that.

If there is anything specific you want to know, by all means, ask away.

(Thanks for the look!)
Keith



^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [RFC] Interpreters (~final) (fwd)
  2002-08-27  9:26 Keith Seitz
@ 2002-08-27 15:01 ` Michael Snyder
  2002-08-27 15:19   ` Keith Seitz
  0 siblings, 1 reply; 16+ messages in thread
From: Michael Snyder @ 2002-08-27 15:01 UTC (permalink / raw)
  To: Keith Seitz; +Cc: gdb-patches

Keith Seitz wrote:
> 
> Ping.

Hi Keith, 

I'm not sure whose domain this is.  /me lacks context.
What is it we're trying to do here?  Provide replacements
to the CLI interpreter?  Lash an extension language into gdb?
Excuse my ignorance, I haven't followed the conversation 
too closely.

Michael


> 
> ---------- Forwarded message ----------
> Date: Tue, 13 Aug 2002 13:22:46 -0700 (PDT)
> From: Keith Seitz <keiths@redhat.com>
> To: gdb-patches@sources.redhat.com
> Subject: [RFC] Interpreters (~final)
> 
> Hi,
> 
> Well, at long last, I think I am ready to try and get some of this work
> approved.
> 
> So, first on the chopping block: interps.c, interps.h.
> 
> ChangeLogs (to be massaged appropriately):
> 2002-08-13  Keith Seitz  <keiths@redhat.com>
> 
>         * interps.c (_initialize_interpreter): Remove ability to set
>         the interpreter. This could really undermine MI clients.
>         * top.c (catcher): Don't worry about interpreter changes.
> 
> 2002-08-12  Keith Seitz  <keiths@redhat.com>
> 
>         * interps.c (_initialize_interpreter): Add completer function
>         to "set interpreter" command.
> 
> 2002-08-12  Keith Seitz  <keiths@redhat.com>
> 
>         * interps.c: Run through gdb_indent.sh
>         * interps.h: Ditto.
> 
> 2002-06-24  Keith Seitz  <keiths@redhat.com>
> 
>         * interps.c: Include gdb-events.h.
>         (clear_interpreter_hooks): Also clear out event handlers.
>         (gdb_set_interpreter): Clear out any hooks/event handlers that
>         may have been installed by old interpreter.
> 
> 2002-06-18  Keith Seitz  <keiths@redhat.com>
> 
>         * interps.h: Add GDB_INTERPRETER_MI1. GDB_INTERPRETER_MI will
>         now be mi version 2.
> 
> 2002-05-28  Keith Seitz  <keiths@redhat.com>
> 
>         * interps.c: New file. (Originally called interpreter.c by Apple)
>         * interps.h: New file. (Originally called interpreter.h by Apple)
> 
> "Patch"
> See appeneded files, interps.h and interps.c
> 
> For the curious, you can play with the whole thing by checking out
> kseitz_interps-20020528-branch, which was last merged with cvs HEAD on 9
> Aug 2002. The branch contains testcases, documentation, etc, too.
> 
> It probably isn't perfect, but it's at least a place to start (IMO). There
> are no regressions with this compared to gdb of 9 Aug 2002.
> 
> Questions/comments welcome.
> Keith
> 
>   ------------------------------------------------------------------------
>                 Name: interps.h
>    interps.h    Type: Plain Text (TEXT/PLAIN)
>             Encoding: BASE64
> 
>                 Name: interps.c
>    interps.c    Type: Plain Text (TEXT/PLAIN)
>             Encoding: BASE64


^ permalink raw reply	[flat|nested] 16+ messages in thread

* [RFC] Interpreters (~final) (fwd)
@ 2002-08-27  9:26 Keith Seitz
  2002-08-27 15:01 ` Michael Snyder
  0 siblings, 1 reply; 16+ messages in thread
From: Keith Seitz @ 2002-08-27  9:26 UTC (permalink / raw)
  To: gdb-patches

[-- Attachment #1: Type: TEXT/PLAIN, Size: 1968 bytes --]

Ping.

---------- Forwarded message ----------
Date: Tue, 13 Aug 2002 13:22:46 -0700 (PDT)
From: Keith Seitz <keiths@redhat.com>
To: gdb-patches@sources.redhat.com
Subject: [RFC] Interpreters (~final)

Hi,

Well, at long last, I think I am ready to try and get some of this work 
approved.

So, first on the chopping block: interps.c, interps.h.

ChangeLogs (to be massaged appropriately):
2002-08-13  Keith Seitz  <keiths@redhat.com>

        * interps.c (_initialize_interpreter): Remove ability to set
        the interpreter. This could really undermine MI clients.
        * top.c (catcher): Don't worry about interpreter changes.

2002-08-12  Keith Seitz  <keiths@redhat.com>

        * interps.c (_initialize_interpreter): Add completer function
        to "set interpreter" command.

2002-08-12  Keith Seitz  <keiths@redhat.com>

        * interps.c: Run through gdb_indent.sh
        * interps.h: Ditto.

2002-06-24  Keith Seitz  <keiths@redhat.com>

        * interps.c: Include gdb-events.h.
        (clear_interpreter_hooks): Also clear out event handlers.
        (gdb_set_interpreter): Clear out any hooks/event handlers that
        may have been installed by old interpreter.

2002-06-18  Keith Seitz  <keiths@redhat.com>

        * interps.h: Add GDB_INTERPRETER_MI1. GDB_INTERPRETER_MI will
        now be mi version 2.

2002-05-28  Keith Seitz  <keiths@redhat.com>

        * interps.c: New file. (Originally called interpreter.c by Apple)
        * interps.h: New file. (Originally called interpreter.h by Apple)

"Patch"
See appeneded files, interps.h and interps.c

For the curious, you can play with the whole thing by checking out 
kseitz_interps-20020528-branch, which was last merged with cvs HEAD on 9 
Aug 2002. The branch contains testcases, documentation, etc, too.

It probably isn't perfect, but it's at least a place to start (IMO). There 
are no regressions with this compared to gdb of 9 Aug 2002.

Questions/comments welcome.
Keith

[-- Attachment #2: Type: TEXT/PLAIN, Size: 3105 bytes --]

/* Manages interpreters for gdb.
   Copyright 2000,2002 Free Software Foundation, Inc.
   Written by Jim Ingham <jingham@apple.com> of Apple Computer, Inc.

   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., 59 Temple Place - Suite 330,
   Boston, MA 02111-1307, USA. */

#ifndef GDB_INTERPRETER_H
#define GDB_INTERPRETER_H

typedef int (*interp_init_ftype) (void *data);
typedef int (*interp_resume_ftype) (void *data);
typedef int (*interp_do_one_event_ftype) (void *data);
typedef int (*interp_suspend_ftype) (void *data);
typedef int (*interp_delete_ftype) (void *data);
typedef int (*interp_prompt_ftype) (void *data, char *new_prompt);
typedef int (*interp_exec_ftype) (void *data, char *command);

struct ui_out;
struct gdb_interpreter;

struct gdb_interpreter_procs
{
  interp_init_ftype init_proc;
  interp_resume_ftype resume_proc;
  interp_do_one_event_ftype do_one_event_proc;
  interp_suspend_ftype suspend_proc;
  interp_delete_ftype delete_proc;
  interp_exec_ftype exec_proc;
  interp_prompt_ftype prompt_proc;
};

extern struct gdb_interpreter
  *gdb_new_interpreter (char *name, void *data, struct ui_out *uiout,
			struct gdb_interpreter_procs *procs);

extern int gdb_add_interpreter (struct gdb_interpreter *interp);
extern int gdb_delete_interpreter (struct gdb_interpreter *interp);
extern int gdb_set_interpreter (struct gdb_interpreter *interp);
extern struct gdb_interpreter *gdb_lookup_interpreter (char *name);
extern struct gdb_interpreter *gdb_current_interpreter ();
extern struct ui_out *gdb_interpreter_ui_out (struct gdb_interpreter *interp);
extern int gdb_current_interpreter_is_named (char *interp_name);
extern int gdb_interpreter_exec (char *command_str);
extern int gdb_interpreter_display_prompt (char *new_prompt);
extern int gdb_interpreter_set_quiet (struct gdb_interpreter *interp,
				      int quiet);
extern int gdb_interpreter_is_quiet (struct gdb_interpreter *interp);
extern struct gdb_interpreter_procs *gdb_interpreter_get_procs (struct
								gdb_interpreter
								*interp);
extern void *gdb_interpreter_get_data (struct gdb_interpreter *interp);
extern int interpreter_do_one_event ();

void clear_interpreter_hooks ();

/* well-known interpreters */
#define GDB_INTERPRETER_CONSOLE		"console"
#define GDB_INTERPRETER_MI0		"mi0"
#define GDB_INTERPRETER_MI1             "mi1"
#define GDB_INTERPRETER_MI		"mi"
#endif /* GDB_INTERPRETER_H */

[-- Attachment #3: Type: TEXT/PLAIN, Size: 18515 bytes --]

/* Manages interpreters for gdb.
   Copyright 2000, 2002 Free Software Foundation, Inc.
   Written by Jim Ingham <jingham@apple.com> of Apple Computer, Inc.

   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., 59 Temple Place - Suite 330,
   Boston, MA 02111-1307, USA. */

/* This is just a first cut at separating out the "interpreter" functions
   of gdb into self-contained modules.  There are a couple of open areas that
   need to be sorted out:

   1) The interpreter explicitly contains a UI_OUT, and can insert itself
   into the event loop, but it doesn't explicitly contain hooks for readline.
   I did this because it seems to me many interpreters won't want to use
   the readline command interface, and it is probably simpler to just let
   them take over the input in their resume proc.  

   2) The event loop insertion is probably wrong.  I just inserted a 
   do_one_event alongside gdb's do_one_event.  This probably will lead
   to one or the other event loop getting starved.  It would be better
   to provide conversion functions for the gdb file handlers, and when
   an interpreter starts up, it grabs all the gdb created file handlers
   and inserts them into its select.  This is more complicated, however,
   and I have run out of time for now.
*/

#include "defs.h"
#include "gdbcmd.h"
#include "ui-out.h"
#include "event-loop.h"
#include "event-top.h"
#include "interps.h"
#include "completer.h"
#include "gdb_string.h"
#include "gdb-events.h"

struct gdb_interpreter
{
  char *name;			/* This is the name in "-i=" and set interpreter. */
  struct gdb_interpreter *next;	/* Interpreters are stored in a linked list, 
				   this is the next one... */
  void *data;			/* This is a cookie that the instance of the 
				   interpreter can use, for instance to call 
				   itself in hook functions */
  int inited;			/* Has the init_proc been run? */
  struct ui_out *interpreter_out;	/* This is the ui_out used to collect 
					   results for this interpreter.  It can 
					   be a formatter for stdout, as is the 
					   case for the console & mi outputs, or it 
					   might be a result formatter. */
  struct gdb_interpreter_procs procs;
  int quiet_p;
};

/* Functions local to this file. */
static void initialize_interps (void);

static void set_interpreter_cmd (char *args, int from_tty,
				 struct cmd_list_element *c);
static void list_interpreter_cmd (char *args, int from_tty);
static void do_set_interpreter (int not_an_fd);
static char **interpreter_completer (char *text, char *word);

/* The magic initialization routine for this module. */

void _initialize_interpreter (void);

/* Variables local to this file: */

static struct gdb_interpreter *interp_list = NULL;
static struct gdb_interpreter *current_interpreter = NULL;

static int interpreter_initialized = 0;

/* gdb_new_interpreter - This allocates space for a new interpreter,
   fills the fields from the inputs, and returns a pointer to the
   interpreter. */

struct gdb_interpreter *
gdb_new_interpreter (char *name,
		     void *data,
		     struct ui_out *uiout,
		     struct gdb_interpreter_procs *procs)
{
  struct gdb_interpreter *new_interp;

  new_interp =
    (struct gdb_interpreter *) xmalloc (sizeof (struct gdb_interpreter));

  new_interp->name = xstrdup (name);
  new_interp->data = data;
  new_interp->interpreter_out = uiout;
  new_interp->quiet_p = 0;
  new_interp->procs.init_proc = procs->init_proc;
  new_interp->procs.resume_proc = procs->resume_proc;
  new_interp->procs.do_one_event_proc = procs->do_one_event_proc;
  new_interp->procs.suspend_proc = procs->suspend_proc;
  new_interp->procs.delete_proc = procs->delete_proc;
  new_interp->procs.exec_proc = procs->exec_proc;
  new_interp->procs.prompt_proc = procs->prompt_proc;
  new_interp->inited = 0;

  return new_interp;
}

/* Add interpreter INTERP to the gdb interpreter list.  If an
   interpreter of the same name is already on the list, then
   the new one is NOT added, and the function returns 0.  Otherwise
   it returns 1. */

int
gdb_add_interpreter (struct gdb_interpreter *interp)
{
  if (!interpreter_initialized)
    initialize_interps ();

  if (gdb_lookup_interpreter (interp->name) != NULL)
    return 0;

  interp->next = interp_list;
  interp_list = interp;

  return 1;
}

/* Looks for the interpreter INTERP in the interpreter list.  If it exists,
   runs the delete_proc, and if this is successful, the INTERP is deleted from
   the interpreter list and the function returns 1.  If the delete_proc fails, the
   function returns -1 and the interpreter is NOT removed from the list.  If the
   interp is not found, 0 is returned. */

int
gdb_delete_interpreter (struct gdb_interpreter *interp)
{
  struct gdb_interpreter *cur_ptr, *prev_ptr;

  if (!interpreter_initialized)
    {
      ui_out_message (uiout, 0,
		      "You can't delete an interp before you have added one!");
      return -1;
    }

  if (interp_list == NULL)
    {
      ui_out_message (uiout, 0, "No interpreters to delete.");
      return -1;
    }

  if (interp_list->next == NULL)
    {
      ui_out_message (uiout, 0, "You can't delete gdb's only intepreter.");
      return -1;
    }

  for (cur_ptr = interp_list, prev_ptr = NULL;
       cur_ptr != NULL; prev_ptr = cur_ptr, cur_ptr = cur_ptr->next)
    {
      if (cur_ptr == interp)
	{
	  /* Can't currently delete the console interpreter... */
	  if (strcmp (interp->name, "console") == 0)
	    {
	      ui_out_message (uiout, 0,
			      "You can't delete the console interpreter.");
	      return -1;
	    }

	  /* If the interpreter is the current interpreter, switch
	     back to the console interpreter */

	  if (interp == current_interpreter)
	    {
	      gdb_set_interpreter (gdb_lookup_interpreter ("console"));
	    }

	  /* Don't delete the interpreter if its delete proc fails */

	  if ((interp->procs.delete_proc != NULL)
	      && (!interp->procs.delete_proc (interp->data)))
	    return -1;

	  if (cur_ptr == interp_list)
	    interp_list = cur_ptr->next;
	  else
	    prev_ptr->next = cur_ptr->next;

	  break;
	}
    }

  if (cur_ptr == NULL)
    return 0;
  else
    return 1;
}

/* This sets the current interpreter to be INTERP.  If INTERP has not
   been initialized, then this will also run the init proc.  If the
   init proc is successful, return 1, if it fails, set the old
   interpreter back in place and return 0.  If we can't restore the
   old interpreter, then raise an internal error, since we are in
   pretty bad shape at this point. */

int
gdb_set_interpreter (struct gdb_interpreter *interp)
{
  struct gdb_interpreter *old_interp = current_interpreter;
  int first_time = 0;


  char buffer[64];

  if (current_interpreter != NULL)
    {
      do_all_continuations ();
      ui_out_flush (uiout);
      if (current_interpreter->procs.suspend_proc
	  && !current_interpreter->procs.suspend_proc (current_interpreter->
						       data))
	{
	  error ("Could not suspend interpreter \"%s\"\n",
		 current_interpreter->name);
	}
    }
  else
    {
      first_time = 1;
    }

  current_interpreter = interp;

  /* We use interpreter_p for the "set interpreter" variable, so we need
     to make sure we have a malloc'ed copy for the set command to free. */
  if (interpreter_p != NULL
      && strcmp (current_interpreter->name, interpreter_p) != 0)
    {
      xfree (interpreter_p);

      interpreter_p = xstrdup (current_interpreter->name);
    }

  uiout = interp->interpreter_out;

  /* Run the init proc.  If it fails, try to restore the old interp. */

  if (!interp->inited)
    {
      if (interp->procs.init_proc != NULL)
	{
	  if (!interp->procs.init_proc (interp->data))
	    {
	      if (!gdb_set_interpreter (old_interp))
		internal_error (__FILE__, __LINE__,
				"Failed to initialize new interp \"%s\" %s",
				interp->name,
				"and could not restore old interp!\n");
	      return 0;
	    }
	  else
	    {
	      interp->inited = 1;
	    }
	}
      else
	{
	  interp->inited = 1;
	}
    }

  /* Clear out any installed interpreter hooks/event handlers. */
  clear_interpreter_hooks ();

  if (interp->procs.resume_proc != NULL
      && (!interp->procs.resume_proc (interp->data)))
    {
      if (!gdb_set_interpreter (old_interp))
	internal_error (__FILE__, __LINE__,
			"Failed to initialize new interp \"%s\" %s",
			interp->name, "and could not restore old interp!\n");
      return 0;
    }

  /* Finally, put up the new prompt to show that we are indeed here. 
     Also, display_gdb_prompt for the console does some readline magic
     which is needed for the console interpreter, at least... */

  if (!first_time)
    {
      if (!gdb_interpreter_is_quiet (interp))
	{
	  sprintf (buffer, "Switching to interpreter \"%.24s\".\n",
		   interp->name);
	  ui_out_text (uiout, buffer);
	}
      display_gdb_prompt (NULL);
    }

  return 1;
}

/*
 * gdb_lookup_interpreter - Looks up the interpreter for NAME.  If
 * no such interpreter exists, return NULL, otherwise return a pointer
 * to the interpreter. 
 */

struct gdb_interpreter *
gdb_lookup_interpreter (char *name)
{
  struct gdb_interpreter *interp;

  if (name == NULL || strlen (name) == 0)
    return NULL;

  for (interp = interp_list; interp != NULL; interp = interp->next)
    {
      if (strcmp (interp->name, name) == 0)
	return interp;
    }

  return NULL;
}

/* Returns the current interpreter. */

struct gdb_interpreter *
gdb_current_interpreter ()
{
  return current_interpreter;
}

struct ui_out *
gdb_interpreter_ui_out (struct gdb_interpreter *interp)
{
  if (interp != NULL)
    return interp->interpreter_out;

  return current_interpreter->interpreter_out;
}

/* Returns true if the current interp is the passed in name. */
int
gdb_current_interpreter_is_named (char *interp_name)
{
  struct gdb_interpreter *current_interp = gdb_current_interpreter ();

  if (current_interp)
    return (strcmp (current_interp->name, interp_name) == 0);

  return 0;
}

/* This is called in display_gdb_prompt.
   If the current interpreter defines a prompt_proc, then that proc is 
   run.  If the proc returns a non-zero value, display_gdb_prompt will
   return without itself displaying the prompt. */

int
gdb_interpreter_display_prompt (char *new_prompt)
{
  if (current_interpreter->procs.prompt_proc == NULL)
    return 0;
  else
    return current_interpreter->procs.prompt_proc (current_interpreter->data,
						   new_prompt);
}

int
gdb_interpreter_is_quiet (struct gdb_interpreter *interp)
{
  if (interp != NULL)
    return interp->quiet_p;
  else
    return current_interpreter->quiet_p;
}

int
gdb_interpreter_set_quiet (struct gdb_interpreter *interp, int quiet)
{
  int old_val = interp->quiet_p;
  interp->quiet_p = quiet;
  return old_val;
}

/* gdb_interpreter_exec - This executes COMMAND_STR in the current 
   interpreter. */

int
gdb_interpreter_exec (char *command_str)
{
  if (current_interpreter->procs.exec_proc != NULL)
    {
      return current_interpreter->procs.exec_proc (current_interpreter->data,
						   command_str);
    }

  return 0;
}

struct gdb_interpreter_procs *
gdb_interpreter_get_procs (struct gdb_interpreter *interp)
{
  if (interp != NULL)
    return &interp->procs;

  return &current_interpreter->procs;
}

void *
gdb_interpreter_get_data (struct gdb_interpreter *interp)
{
  if (interp != NULL)
    return interp->data;

  return current_interpreter->data;
}

int
interpreter_do_one_event ()
{
  if (current_interpreter->procs.do_one_event_proc == NULL)
    return 0;

  return current_interpreter->procs.do_one_event_proc (current_interpreter->
						       data);
}

/* A convenience routine that nulls out all the
   common command hooks.  Use it when removing your interpreter in its 
   suspend proc. */

void
clear_interpreter_hooks ()
{
  init_ui_hook = 0;
  print_frame_info_listing_hook = 0;
  /*print_frame_more_info_hook = 0; */
  query_hook = 0;
  warning_hook = 0;
  create_breakpoint_hook = 0;
  delete_breakpoint_hook = 0;
  modify_breakpoint_hook = 0;
  interactive_hook = 0;
  registers_changed_hook = 0;
  readline_begin_hook = 0;
  readline_hook = 0;
  readline_end_hook = 0;
  register_changed_hook = 0;
  memory_changed_hook = 0;
  context_hook = 0;
  target_wait_hook = 0;
  call_command_hook = 0;
  error_hook = 0;
  error_begin_hook = 0;
  command_loop_hook = 0;
  clear_gdb_event_hooks ();
}

/* This is a lazy init routine, called the first time
   the interpreter module is used.  I put it here just in case, but I haven't
   thought of a use for it yet.  I will probably bag it soon, since I don't
   think it will be necessary. */

static void
initialize_interps (void)
{
  interpreter_initialized = 1;
  /* Don't know if anything needs to be done here... */
}

/* set_interpreter_cmd - This implements "set interpreter foo". */

static void
set_interpreter_cmd (char *args, int from_tty, struct cmd_list_element *c)
{
  struct gdb_interpreter *interp_ptr;

  dont_repeat ();

  if (cmd_type (c) != set_cmd)
    return;

  interp_ptr = gdb_lookup_interpreter (interpreter_p);
  if (interp_ptr != NULL)
    {
      if (!gdb_set_interpreter (interp_ptr))
	error ("\nCould not switch to interpreter \"%s\", %s%s\".\n",
	       interp_ptr->name, "reverting to interpreter \"",
	       current_interpreter->name);
    }
  else
    {
      char *bad_name = interpreter_p;
      interpreter_p = xstrdup (current_interpreter->name);
      error ("Could not find interpreter \"%s\".", bad_name);
    }
}

/* list_interpreter_cmd - This implements "info interpreters". */

void
list_interpreter_cmd (char *args, int from_tty)
{
  struct gdb_interpreter *interp_ptr;

  ui_out_list_begin (uiout, "interpreters");
  for (interp_ptr = interp_list; interp_ptr != NULL;
       interp_ptr = interp_ptr->next)
    {
      ui_out_text (uiout, "  * ");
      ui_out_field_string (uiout, "interpreter", interp_ptr->name);
      ui_out_text (uiout, "\n");
    }
  ui_out_list_end (uiout);
}

void
interpreter_exec_cmd (char *args, int from_tty)
{
  struct gdb_interpreter *old_interp, *interp_to_use;
  char **prules = NULL;
  char **trule = NULL;
  unsigned int nrules;
  unsigned int i;
  int old_quiet;

  prules = buildargv (args);
  if (prules == NULL)
    {
      error ("unable to parse arguments");
    }

  nrules = 0;
  if (prules != NULL)
    {
      for (trule = prules; *trule != NULL; trule++)
	{
	  nrules++;
	}
    }

  if (nrules < 2)
    error ("usage: interpreter-exec <interpreter> [ <command> ... ]");

  old_interp = gdb_current_interpreter ();

  interp_to_use = gdb_lookup_interpreter (prules[0]);
  if (interp_to_use == NULL)
    error ("Could not find interpreter \"%s\".", prules[0]);

  old_quiet = gdb_interpreter_set_quiet (interp_to_use, 1);

  if (!gdb_set_interpreter (interp_to_use))
    error ("Could not switch to interpreter \"%s\".", prules[0]);

  for (i = 1; i < nrules; i++)
    {
      if (!gdb_interpreter_exec (prules[i]))
	{
	  gdb_set_interpreter (old_interp);
	  gdb_interpreter_set_quiet (interp_to_use, old_quiet);
	  error
	    ("interpreter-exec: mi_interpreter_execute: error in command: \"%s\".",
	     prules[i]);
	  break;
	}
    }

  gdb_set_interpreter (old_interp);
  gdb_interpreter_set_quiet (interp_to_use, old_quiet);
}

/* List the possible interpreters which could complete the given text. */

static char **
interpreter_completer (char *text, char *word)
{
  int alloced, textlen;
  int num_matches;
  char **matches;
  struct gdb_interpreter *interp;

  /* We expect only a very limited number of interpreters, so just
     allocate room for all of them. */
  for (interp = interp_list; interp != NULL; interp = interp->next)
    ++alloced;
  matches = (char **) xmalloc (alloced * sizeof (char *));

  num_matches = 0;
  textlen = strlen (text);
  for (interp = interp_list; interp != NULL; interp = interp->next)
    {
      if (strncmp (interp->name, text, textlen) == 0)
	{
	  matches[num_matches] =
	    (char *) xmalloc (strlen (word) + strlen (interp->name) + 1);
	  if (word == text)
	    strcpy (matches[num_matches], interp->name);
	  else if (word > text)
	    {
	      /* Return some portion of interp->name */
	      strcpy (matches[num_matches], interp->name + (word - text));
	    }
	  else
	    {
	      /* Return some of text plus interp->name */
	      strncpy (matches[num_matches], word, text - word);
	      matches[num_matches][text - word] = '\0';
	      strcat (matches[num_matches], interp->name);
	    }
	  ++num_matches;
	}
    }

  if (num_matches == 0)
    {
      xfree (matches);
      matches = NULL;
    }
  else if (num_matches < alloced)
    {
      matches = (char **) xrealloc ((char *) matches, ((num_matches + 1)
						       * sizeof (char *)));
      matches[num_matches] = NULL;
    }

  return matches;
}

/* This just adds the "set interpreter" and "info interpreters" commands. */

void
_initialize_interpreter (void)
{
  struct cmd_list_element *c;

  c = add_cmd ("interpreter-exec", class_support,
	       interpreter_exec_cmd,
	       "Execute a command in an interpreter.  It takes two arguments:\n\
The first argument is the name of the interpreter to use.\n\
The second argument is the command to execute.\n", &cmdlist);
  set_cmd_completer (c, interpreter_completer);
}

^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2002-09-30 22:58 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2002-09-06  8:40 [RFC] Interpreters (~final) (fwd) Keith Seitz
2002-09-22 15:40 ` Elena Zannoni
2002-09-23 11:57   ` Keith Seitz
2002-09-23 12:44     ` Keith Seitz
2002-09-30 11:35       ` Elena Zannoni
2002-09-30 15:58       ` Elena Zannoni
     [not found] <1030485672.17451.ezmlm@sources.redhat.com>
2002-08-27 15:21 ` Jim Ingham
  -- strict thread matches above, loose matches on Subject: below --
2002-08-27  9:26 Keith Seitz
2002-08-27 15:01 ` Michael Snyder
2002-08-27 15:19   ` Keith Seitz
2002-08-28  7:14     ` Eli Zaretskii
2002-08-28  8:37       ` Keith Seitz
2002-08-28  9:03         ` Eli Zaretskii
2002-08-28 13:33         ` Michael Snyder
2002-08-28 17:13           ` Andrew Cagney
2002-08-28 22:09             ` Eli Zaretskii

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox