Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
From: Keith Seitz <keiths@redhat.com>
To: Elena Zannoni <ezannoni@redhat.com>
Cc: gdb-patches@sources.redhat.com
Subject: Re: [RFC] Interpreters (~final) (fwd)
Date: Mon, 23 Sep 2002 12:44:00 -0000	[thread overview]
Message-ID: <Pine.LNX.4.44.0209231251060.10013-200000@lindt.uglyboxes.com> (raw)
In-Reply-To: <Pine.LNX.4.44.0209231205280.10013-100000@lindt.uglyboxes.com>

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

  reply	other threads:[~2002-09-23 19:44 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2002-09-06  8:40 Keith Seitz
2002-09-22 15:40 ` Elena Zannoni
2002-09-23 11:57   ` Keith Seitz
2002-09-23 12:44     ` Keith Seitz [this message]
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

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=Pine.LNX.4.44.0209231251060.10013-200000@lindt.uglyboxes.com \
    --to=keiths@redhat.com \
    --cc=ezannoni@redhat.com \
    --cc=gdb-patches@sources.redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox