OSDN Git Service

Initial revision
authorjsm <jsm>
Thu, 3 Feb 2000 04:14:36 +0000 (04:14 +0000)
committerjsm <jsm>
Thu, 3 Feb 2000 04:14:36 +0000 (04:14 +0000)
gdb/ui-out.c [new file with mode: 0644]
gdb/ui-out.h [new file with mode: 0644]
gdb/varobj.c [new file with mode: 0644]
gdb/varobj.h [new file with mode: 0644]
gdb/wrapper.c [new file with mode: 0644]
gdb/wrapper.h [new file with mode: 0644]

diff --git a/gdb/ui-out.c b/gdb/ui-out.c
new file mode 100644 (file)
index 0000000..9e40011
--- /dev/null
@@ -0,0 +1,1007 @@
+/* Output generating routines for GDB.
+   Copyright 1999, 2000 Free Software Foundation, Inc.
+   Contributed by Cygnus Solutions.
+   Written by Fernando Nasser for Cygnus.
+
+   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 "gdb_string.h"
+#include "expression.h"                /* For language.h */
+#include "language.h"
+#include "ui-out.h"
+
+/* Convenience macro for allocting typesafe memory. */
+
+#undef XMALLOC
+#define XMALLOC(TYPE) (TYPE*) xmalloc (sizeof (TYPE))
+
+/* table header structures */
+
+struct ui_out_hdr
+  {
+    int colno;
+    int width;
+    int alignment;
+    char *colhdr;
+    struct ui_out_hdr *next;
+  };
+
+/* The ui_out structure */
+/* Any change here requires a corresponding one in the initialization
+   of the default uiout, which is statically initialized */
+
+struct ui_out
+  {
+    int flags;
+    /* specific implementation of ui-out */
+    struct ui_out_impl *impl;
+    struct ui_out_data *data;
+
+    /* if on, a table is being generated */
+    int table_flag;
+
+    /* if on, the body of a table is being generated */
+    int body_flag;
+
+    /* number of table columns (as specified in the table_begin call) */
+    int table_columns;
+
+    /* strinf identifying the table (as specified in the table_begin call) */
+    char *table_id;
+
+    /* if on, a list is being generated.  The value is the level of nesting */
+    int list_flag;
+
+    /* we count each field; the first element is for non-list fields */
+    int field_count[5];
+
+    /* points to the first header (if any) */
+    struct ui_out_hdr *headerfirst;
+
+    /* points to the last header (if any) */
+    struct ui_out_hdr *headerlast;
+
+    /* points to header of next column to format */
+    struct ui_out_hdr *headercurr;
+
+  };
+
+/* These are the default implementation functions */
+
+static void default_table_begin (struct ui_out *uiout, int nbrofcols,
+                                char *tblid);
+static void default_table_body (struct ui_out *uiout);
+static void default_table_end (struct ui_out *uiout);
+static void default_table_header (struct ui_out *uiout, int width,
+                                 enum ui_align alig, char *colhdr);
+static void default_list_begin (struct ui_out *uiout, int list_flag,
+                               char *lstid);
+static void default_list_end (struct ui_out *uiout, int list_flag);
+static void default_field_int (struct ui_out *uiout, int fldno, int width,
+                              enum ui_align alig, char *fldname, int value);
+static void default_field_skip (struct ui_out *uiout, int fldno, int width,
+                               enum ui_align alig, char *fldname);
+static void default_field_string (struct ui_out *uiout, int fldno, int width,
+                                 enum ui_align align, char *fldname,
+                                 const char *string);
+static void default_field_fmt (struct ui_out *uiout, int fldno,
+                              int width, enum ui_align align,
+                              char *fldname, char *format, va_list args);
+static void default_spaces (struct ui_out *uiout, int numspaces);
+static void default_text (struct ui_out *uiout, char *string);
+static void default_message (struct ui_out *uiout, int verbosity, char *format,
+                            va_list args);
+static void default_wrap_hint (struct ui_out *uiout, char *identstring);
+static void default_flush (struct ui_out *uiout);
+
+/* This is the default ui-out implementation functions vector */
+
+struct ui_out_impl default_ui_out_impl =
+{
+  default_table_begin,
+  default_table_body,
+  default_table_end,
+  default_table_header,
+  default_list_begin,
+  default_list_end,
+  default_field_int,
+  default_field_skip,
+  default_field_string,
+  default_field_fmt,
+  default_spaces,
+  default_text,
+  default_message,
+  default_wrap_hint,
+  default_flush
+};
+
+/* The default ui_out */
+
+struct ui_out def_uiout =
+{
+  0,                           /* flags */
+  &default_ui_out_impl,                /* impl */
+};
+
+/* Pointer to current ui_out */
+/* FIXME: This should not be a global, but something passed down from main.c
+   or top.c */
+
+struct ui_out *uiout = &def_uiout;
+
+/* These are the interfaces to implementation functions */
+
+static void uo_table_begin (struct ui_out *uiout, int nbrofcols, char *tblid);
+static void uo_table_body (struct ui_out *uiout);
+static void uo_table_end (struct ui_out *uiout);
+static void uo_table_header (struct ui_out *uiout, int width,
+                            enum ui_align align, char *colhdr);
+static void uo_list_begin (struct ui_out *uiout, int list_flag, char *lstid);
+static void uo_list_end (struct ui_out *uiout, int list_flag);
+static void uo_field_int (struct ui_out *uiout, int fldno, int width,
+                         enum ui_align align, char *fldname, int value);
+static void uo_field_skip (struct ui_out *uiout, int fldno, int width,
+                          enum ui_align align, char *fldname);
+static void uo_field_string (struct ui_out *uiout, int fldno, int width,
+                         enum ui_align align, char *fldname, const char *string);
+static void uo_field_fmt (struct ui_out *uiout, int fldno, int width,
+                         enum ui_align align, char *fldname,
+                         char *format, va_list args);
+static void uo_spaces (struct ui_out *uiout, int numspaces);
+static void uo_text (struct ui_out *uiout, char *string);
+static void uo_message (struct ui_out *uiout, int verbosity,
+                       char *format, va_list args);
+static void uo_wrap_hint (struct ui_out *uiout, char *identstring);
+static void uo_flush (struct ui_out *uiout);
+
+/* Prototypes for local functions */
+
+extern void _initialize_ui_out (void);
+static void append_header_to_list (struct ui_out *uiout, int width, int alignment, char *colhdr);
+static int get_curr_header (struct ui_out *uiout, int *colno, int *width,
+                           int *alignment, char **colhdr);
+static void clear_header_list (struct ui_out *uiout);
+static void verify_field_proper_position (struct ui_out *uiout);
+static void verify_field_alignment (struct ui_out *uiout, int fldno, int *width, int *alignment);
+
+static void init_ui_out_state (struct ui_out *uiout);
+
+/* exported functions (ui_out API) */
+
+/* Mark beginning of a table */
+
+void
+ui_out_table_begin (uiout, nbrofcols, tblid)
+     struct ui_out *uiout;
+     int nbrofcols;
+     char *tblid;
+{
+  if (uiout->table_flag)
+    internal_error ("gdb/ui_out.c: tables cannot be nested; table_begin found before \
+previous table_end.");
+
+  uiout->table_flag = 1;
+  uiout->table_columns = nbrofcols;
+  if (tblid != NULL)
+    uiout->table_id = xstrdup (tblid);
+  else
+    uiout->table_id = NULL;
+  clear_header_list (uiout);
+
+  uo_table_begin (uiout, nbrofcols, uiout->table_id);
+}
+
+void
+ui_out_table_body (uiout)
+     struct ui_out *uiout;
+{
+  if (!uiout->table_flag)
+    internal_error ("gdb/ui_out.c: table_body outside a table is not valid; it must be \
+after a table_begin and before a table_end.");
+  if (uiout->body_flag)
+    internal_error ("gdb/ui_out.c: extra table_body call not allowed; there must be \
+only one table_body after a table_begin and before a table_end.");
+  if (uiout->headercurr->colno != uiout->table_columns)
+    internal_error ("gdb/ui_out.c: number of headers differ from number of table \
+columns.");
+
+  uiout->body_flag = 1;
+  uiout->headercurr = uiout->headerfirst;
+
+  uo_table_body (uiout);
+}
+
+void
+ui_out_table_end (uiout)
+     struct ui_out *uiout;
+{
+  if (!uiout->table_flag)
+    internal_error ("gdb/ui_out.c: misplaced table_end or missing table_begin.");
+
+  uiout->body_flag = 0;
+  uiout->table_flag = 0;
+
+  uo_table_end (uiout);
+
+  if (uiout->table_id)
+    free (uiout->table_id);
+  clear_header_list (uiout);
+}
+
+void
+ui_out_table_header (uiout, width, alignment, colhdr)
+     struct ui_out *uiout;
+     int width;
+     enum ui_align alignment;
+     char *colhdr;
+{
+  if (!uiout->table_flag || uiout->body_flag)
+    internal_error ("ui_out: table header must be specified after table_begin \
+and before table_body.");
+
+  append_header_to_list (uiout, width, alignment, colhdr);
+
+  uo_table_header (uiout, width, alignment, colhdr);
+}
+
+void
+ui_out_list_begin (uiout, lstid)
+     struct ui_out *uiout;
+     char *lstid;
+{
+  if (uiout->table_flag && !uiout->body_flag)
+    internal_error ("ui_out: table header or table_body expected; lists must be \
+specified after table_body.");
+  if (uiout->list_flag >= 4)
+    internal_error ("ui_out: list depth exceeded; only 4 levels of lists can be \
+nested.");
+
+  uiout->list_flag++;
+  uiout->field_count[uiout->list_flag] = 0;
+  if (uiout->table_flag && (uiout->list_flag == 1))
+    uiout->headercurr = uiout->headerfirst;
+
+  uo_list_begin (uiout, uiout->list_flag, lstid);
+}
+
+void
+ui_out_list_end (uiout)
+     struct ui_out *uiout;
+{
+  if (!uiout->list_flag)
+    internal_error ("ui_out: misplaced list_end; there is no list to be closed.");
+
+  uo_list_end (uiout, uiout->list_flag);
+
+  uiout->list_flag--;
+}
+
+void
+ui_out_field_int (uiout, fldname, value)
+     struct ui_out *uiout;
+     char *fldname;
+     int value;
+{
+  int fldno;
+  int width;
+  int align;
+
+  verify_field_proper_position (uiout);
+
+  uiout->field_count[uiout->list_flag] += 1;
+  fldno = uiout->field_count[uiout->list_flag];
+
+  verify_field_alignment (uiout, fldno, &width, &align);
+
+  uo_field_int (uiout, fldno, width, align, fldname, value);
+}
+
+void
+ui_out_field_core_addr (uiout, fldname, address)
+     struct ui_out *uiout;
+     char *fldname;
+     CORE_ADDR address;
+{
+  char addstr[20];
+
+  /* FIXME-32x64: need a print_address_numeric with field width */
+  /* print_address_numeric (address, 1, local_stream); */
+  strcpy (addstr, local_hex_string_custom ((unsigned long) address, "08l"));
+
+  ui_out_field_string (uiout, fldname, addstr);
+}
+
+void
+ui_out_field_stream (uiout, fldname, buf)
+     struct ui_out *uiout;
+     char *fldname;
+     struct ui_stream *buf;
+{
+  long length;
+  char *buffer = ui_file_xstrdup (buf->stream, &length);
+  struct cleanup *old_cleanup = make_cleanup (free, buffer);
+  if (length > 0)
+    ui_out_field_string (uiout, fldname, buffer);
+  else
+    ui_out_field_skip (uiout, fldname);
+  ui_file_rewind (buf->stream);
+  do_cleanups (old_cleanup);
+}
+
+/* used to ommit a field */
+
+void
+ui_out_field_skip (uiout, fldname)
+     struct ui_out *uiout;
+     char *fldname;
+{
+  int fldno;
+  int width;
+  int align;
+
+  verify_field_proper_position (uiout);
+
+  uiout->field_count[uiout->list_flag] += 1;
+  fldno = uiout->field_count[uiout->list_flag];
+
+  verify_field_alignment (uiout, fldno, &width, &align);
+
+  uo_field_skip (uiout, fldno, width, align, fldname);
+}
+
+void
+ui_out_field_string (struct ui_out *uiout,
+                    char *fldname,
+                    const char *string)
+{
+  int fldno;
+  int width;
+  int align;
+
+  verify_field_proper_position (uiout);
+
+  uiout->field_count[uiout->list_flag] += 1;
+  fldno = uiout->field_count[uiout->list_flag];
+
+  verify_field_alignment (uiout, fldno, &width, &align);
+
+  uo_field_string (uiout, fldno, width, align, fldname, string);
+}
+
+/* VARARGS */
+void
+ui_out_field_fmt (struct ui_out *uiout, char *fldname, char *format,...)
+{
+  va_list args;
+  int fldno;
+  int width;
+  int align;
+
+  verify_field_proper_position (uiout);
+
+  uiout->field_count[uiout->list_flag] += 1;
+  fldno = uiout->field_count[uiout->list_flag];
+
+  /* will not align, but has to call anyway */
+  verify_field_alignment (uiout, fldno, &width, &align);
+
+  va_start (args, format);
+
+  uo_field_fmt (uiout, fldno, width, align, fldname, format, args);
+
+  va_end (args);
+}
+
+void
+ui_out_spaces (uiout, numspaces)
+     struct ui_out *uiout;
+     int numspaces;
+{
+  uo_spaces (uiout, numspaces);
+}
+
+void
+ui_out_text (uiout, string)
+     struct ui_out *uiout;
+     char *string;
+{
+  uo_text (uiout, string);
+}
+
+void
+ui_out_message (struct ui_out *uiout, int verbosity, char *format,...)
+{
+  va_list args;
+
+  va_start (args, format);
+
+  uo_message (uiout, verbosity, format, args);
+
+  va_end (args);
+}
+
+struct ui_stream *
+ui_out_stream_new (uiout)
+     struct ui_out *uiout;
+{
+  struct ui_stream *tempbuf;
+
+  tempbuf = XMALLOC (struct ui_stream);
+  tempbuf->uiout = uiout;
+  tempbuf->stream = mem_fileopen ();
+  return tempbuf;
+}
+
+void
+ui_out_stream_delete (buf)
+     struct ui_stream *buf;
+{
+  ui_file_delete (buf->stream);
+  free (buf);
+}
+
+static void
+do_stream_delete (void *buf)
+{
+  ui_out_stream_delete (buf);
+}
+
+struct cleanup *
+make_cleanup_ui_out_stream_delete (struct ui_stream *buf)
+{
+  return make_cleanup (do_stream_delete, buf);
+}
+
+
+void
+ui_out_wrap_hint (uiout, identstring)
+     struct ui_out *uiout;
+     char *identstring;
+{
+  uo_wrap_hint (uiout, identstring);
+}
+
+void
+ui_out_flush (uiout)
+     struct ui_out *uiout;
+{
+  uo_flush (uiout);
+}
+
+/* set the flags specified by the mask given */
+int
+ui_out_set_flags (uiout, mask)
+     struct ui_out *uiout;
+     int mask;
+{
+  int oldflags;
+
+  uiout->flags != mask;
+
+  return oldflags;
+}
+
+/* clear the flags specified by the mask given */
+int
+ui_out_clear_flags (uiout, mask)
+     struct ui_out *uiout;
+     int mask;
+{
+  int oldflags;
+
+  uiout->flags &= ~mask;
+
+  return oldflags;
+}
+
+/* test the flags against the mask given */
+int
+ui_out_test_flags (uiout, mask)
+     struct ui_out *uiout;
+     int mask;
+{
+  return (uiout->flags & mask);
+}
+
+/* obtain the current verbosity level (as stablished by the
+   'set verbositylevel' command */
+
+int
+ui_out_get_verblvl (uiout)
+     struct ui_out *uiout;
+{
+  /* FIXME: not implemented yet */
+  return 0;
+}
+
+#if 0
+void
+ui_out_result_begin (uiout, class)
+     struct ui_out *uiout;
+     char *class;
+{
+}
+
+void
+ui_out_result_end (uiout)
+     struct ui_out *uiout;
+{
+}
+
+void
+ui_out_info_begin (uiout, class)
+     struct ui_out *uiout;
+     char *class;
+{
+}
+
+void
+ui_out_info_end (uiout)
+     struct ui_out *uiout;
+{
+}
+
+void
+ui_out_notify_begin (uiout, class)
+     struct ui_out *uiout;
+     char *class;
+{
+}
+
+void
+ui_out_notify_end (uiout)
+     struct ui_out *uiout;
+{
+}
+
+void
+ui_out_error_begin (uiout, class)
+     struct ui_out *uiout;
+     char *class;
+{
+}
+
+void
+ui_out_error_end (uiout)
+     struct ui_out *uiout;
+{
+}
+#endif
+
+#if 0
+void
+gdb_error (ui_out * uiout, int severity, char *format,...)
+{
+  va_list args;
+}
+
+void
+gdb_query (uiout, qflags, qprompt)
+     struct ui_out *uiout;
+     int flags;
+     char *qprompt;
+{
+}
+#endif
+
+/* default gdb-out hook functions */
+
+static void
+default_table_begin (uiout, nbrofcols, tblid)
+     struct ui_out *uiout;
+     int nbrofcols;
+     char *tblid;
+{
+}
+
+static void
+default_table_body (uiout)
+     struct ui_out *uiout;
+{
+}
+
+static void
+default_table_end (uiout)
+     struct ui_out *uiout;
+{
+}
+
+static void
+default_table_header (uiout, width, alignment, colhdr)
+     struct ui_out *uiout;
+     int width;
+     enum ui_align alignment;
+     char *colhdr;
+{
+}
+
+static void
+default_list_begin (uiout, list_flag, lstid)
+     struct ui_out *uiout;
+     int list_flag;
+     char *lstid;
+{
+}
+
+static void
+default_list_end (uiout, list_flag)
+     struct ui_out *uiout;
+     int list_flag;
+{
+}
+
+static void
+default_field_int (uiout, fldno, width, align, fldname, value)
+     struct ui_out *uiout;
+     int fldno;
+     int width;
+     enum ui_align align;
+     char *fldname;
+     int value;
+{
+}
+
+static void
+default_field_skip (uiout, fldno, width, align, fldname)
+     struct ui_out *uiout;
+     int fldno;
+     int width;
+     enum ui_align align;
+     char *fldname;
+{
+}
+
+static void
+default_field_string (struct ui_out *uiout,
+                     int fldno,
+                     int width,
+                     enum ui_align align,
+                     char *fldname,
+                     const char *string)
+{
+}
+
+static void
+default_field_fmt (uiout, fldno, width, align, fldname, format, args)
+     struct ui_out *uiout;
+     int fldno;
+     int width;
+     enum ui_align align;
+     char *fldname;
+     char *format;
+     va_list args;
+{
+}
+
+static void
+default_spaces (uiout, numspaces)
+     struct ui_out *uiout;
+     int numspaces;
+{
+}
+
+static void
+default_text (uiout, string)
+     struct ui_out *uiout;
+     char *string;
+{
+}
+
+static void
+default_message (uiout, verbosity, format, args)
+     struct ui_out *uiout;
+     int verbosity;
+     char *format;
+     va_list args;
+{
+}
+
+static void
+default_wrap_hint (uiout, identstring)
+     struct ui_out *uiout;
+     char *identstring;
+{
+}
+
+static void
+default_flush (uiout)
+     struct ui_out *uiout;
+{
+}
+
+/* Interface to the implementation functions */
+
+void
+uo_table_begin (struct ui_out *uiout, int nbrofcols, char *tblid)
+{
+  if (!uiout->impl->table_begin)
+    return;
+  uiout->impl->table_begin (uiout, nbrofcols, tblid);
+}
+
+void
+uo_table_body (struct ui_out *uiout)
+{
+  if (!uiout->impl->table_body)
+    return;
+  uiout->impl->table_body (uiout);
+}
+
+void
+uo_table_end (struct ui_out *uiout)
+{
+  if (!uiout->impl->table_end)
+    return;
+  uiout->impl->table_end (uiout);
+}
+
+void
+uo_table_header (struct ui_out *uiout, int width, enum ui_align align, char *colhdr)
+{
+  if (!uiout->impl->table_header)
+    return;
+  uiout->impl->table_header (uiout, width, align, colhdr);
+}
+
+void
+uo_list_begin (struct ui_out *uiout, int list_flag, char *lstid)
+{
+  if (!uiout->impl->list_begin)
+    return;
+  uiout->impl->list_begin (uiout, list_flag, lstid);
+}
+
+void
+uo_list_end (struct ui_out *uiout, int list_flag)
+{
+  if (!uiout->impl->list_end)
+    return;
+  uiout->impl->list_end (uiout, list_flag);
+}
+
+void
+uo_field_int (struct ui_out *uiout, int fldno, int width, enum ui_align align, char *fldname, int value)
+{
+  if (!uiout->impl->field_int)
+    return;
+  uiout->impl->field_int (uiout, fldno, width, align, fldname, value);
+}
+
+void
+uo_field_skip (struct ui_out *uiout, int fldno, int width, enum ui_align align, char *fldname)
+{
+  if (!uiout->impl->field_skip)
+    return;
+  uiout->impl->field_skip (uiout, fldno, width, align, fldname);
+}
+
+void
+uo_field_string (struct ui_out *uiout, int fldno, int width,
+                enum ui_align align, char *fldname, const char *string)
+{
+  if (!uiout->impl->field_string)
+    return;
+  uiout->impl->field_string (uiout, fldno, width, align, fldname, string);
+}
+
+void
+uo_field_fmt (struct ui_out *uiout, int fldno, int width, enum ui_align align, char *fldname, char *format, va_list args)
+{
+  if (!uiout->impl->field_fmt)
+    return;
+  uiout->impl->field_fmt (uiout, fldno, width, align, fldname, format, args);
+}
+
+void
+uo_spaces (struct ui_out *uiout, int numspaces)
+{
+  if (!uiout->impl->spaces)
+    return;
+  uiout->impl->spaces (uiout, numspaces);
+}
+
+void
+uo_text (struct ui_out *uiout, char *string)
+{
+  if (!uiout->impl->text)
+    return;
+  uiout->impl->text (uiout, string);
+}
+
+void
+uo_message (struct ui_out *uiout, int verbosity, char *format, va_list args)
+{
+  if (!uiout->impl->message)
+    return;
+  uiout->impl->message (uiout, verbosity, format, args);
+}
+
+void
+uo_wrap_hint (struct ui_out *uiout, char *identstring)
+{
+  if (!uiout->impl->wrap_hint)
+    return;
+  uiout->impl->wrap_hint (uiout, identstring);
+}
+
+void
+uo_flush (struct ui_out *uiout)
+{
+  if (!uiout->impl->flush)
+    return;
+  uiout->impl->flush (uiout);
+}
+
+/* local functions */
+
+/* list of column headers manipulation routines */
+
+static void
+clear_header_list (uiout)
+     struct ui_out *uiout;
+{
+  while (uiout->headerfirst != NULL)
+    {
+      uiout->headercurr = uiout->headerfirst;
+      uiout->headerfirst = uiout->headerfirst->next;
+      if (uiout->headercurr->colhdr != NULL)
+       free (uiout->headercurr->colhdr);
+      free (uiout->headercurr);
+    }
+  uiout->headerlast = NULL;
+  uiout->headercurr = NULL;
+}
+
+static void
+append_header_to_list (struct ui_out *uiout,
+                      int width,
+                      int alignment,
+                      char *colhdr)
+{
+  struct ui_out_hdr *temphdr;
+
+  temphdr = XMALLOC (struct ui_out_hdr);
+  temphdr->width = width;
+  temphdr->alignment = alignment;
+  /* we have to copy the column title as the original may be an automatic */
+  if (colhdr != NULL)
+    {
+      temphdr->colhdr = xmalloc (strlen (colhdr) + 1);
+      strcpy (temphdr->colhdr, colhdr);
+    }
+  temphdr->next = NULL;
+  if (uiout->headerfirst == NULL)
+    {
+      temphdr->colno = 1;
+      uiout->headerfirst = temphdr;
+      uiout->headerlast = temphdr;
+    }
+  else
+    {
+      temphdr->colno = uiout->headerlast->colno + 1;
+      uiout->headerlast->next = temphdr;
+      uiout->headerlast = temphdr;
+    }
+  uiout->headercurr = uiout->headerlast;
+}
+
+/* returns 0 if there is no more headers */
+
+static int
+get_curr_header (struct ui_out *uiout,
+                int *colno,
+                int *width,
+                int *alignment,
+                char **colhdr)
+{
+  /* There may be no headers at all or we may have used all columns */
+  if (uiout->headercurr == NULL)
+    return 0;
+  *colno = uiout->headercurr->colno;
+  *width = uiout->headercurr->width;
+  *alignment = uiout->headercurr->alignment;
+  *colhdr = uiout->headercurr->colhdr;
+  uiout->headercurr = uiout->headercurr->next;
+  return 1;
+}
+
+/* makes sure the field_* calls were properly placed */
+
+static void
+verify_field_proper_position (struct ui_out *uiout)
+{
+  if (uiout->table_flag)
+    {
+      if (!uiout->body_flag)
+       internal_error ("ui_out: table_body missing; table fields must be \
+specified after table_body and inside a list.");
+      if (!uiout->list_flag)
+       internal_error ("ui_out: list_begin missing; table fields must be \
+specified after table_body and inside a list.");
+    }
+}
+
+/* determines what is the alignment policy */
+
+static void
+verify_field_alignment (struct ui_out *uiout,
+                       int fldno,
+                       int *width,
+                       int *align)
+{
+  int colno;
+  char *text;
+
+  if (uiout->table_flag
+      && get_curr_header (uiout, &colno, width, align, &text))
+    {
+      if (fldno != colno)
+       internal_error ("gdb/ui-out.c: ui-out internal error in handling headers.");
+    }
+  else
+    {
+      *width = 0;
+      *align = ui_noalign;
+    }
+}
+
+/* access to ui_out format private members */
+
+void
+ui_out_get_field_separator (uiout)
+     struct ui_out *uiout;
+{
+}
+
+/* Access to ui-out members data */
+
+struct ui_out_data *
+ui_out_data (struct ui_out *uiout)
+{
+  return uiout->data;
+}
+
+/* initalize private members at startup */
+
+struct ui_out *
+ui_out_new (struct ui_out_impl *impl,
+           struct ui_out_data *data,
+           int flags)
+{
+  struct ui_out *uiout = XMALLOC (struct ui_out);
+  uiout->data = data;
+  uiout->impl = impl;
+  uiout->flags = flags;
+  uiout->table_flag = 0;
+  uiout->body_flag = 0;
+  uiout->list_flag = 0;
+  uiout->field_count[0] = 0;
+  uiout->headerfirst = NULL;
+  uiout->headerlast = NULL;
+  uiout->headercurr = NULL;
+  return uiout;
+}
+
+/* standard gdb initialization hook */
+
+void
+_initialize_ui_out ()
+{
+  /* nothing needs to be done */
+}
diff --git a/gdb/ui-out.h b/gdb/ui-out.h
new file mode 100644 (file)
index 0000000..d8db588
--- /dev/null
@@ -0,0 +1,221 @@
+/* Output generating routines for GDB.
+   Copyright 1999, 2000 Free Software Foundation, Inc.
+   Contributed by Cygnus Solutions.
+   Written by Fernando Nasser for Cygnus.
+
+   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 UI_OUT_H
+#define UI_OUT_H 1
+
+/* The ui_out structure */
+
+#if __STDC__
+struct ui_out;
+struct ui_out_data;
+#endif
+
+
+/* the current ui_out */
+
+/* FIXME: This should not be a global but something passed down from main.c
+   or top.c */
+extern struct ui_out *uiout;
+
+/* alignment enum */
+enum ui_align
+  {
+    ui_left = -1,
+    ui_center,
+    ui_right,
+    ui_noalign
+  };
+
+/* flags enum */
+enum ui_flags
+  {
+    ui_from_tty = 1,
+    ui_source_list = 2
+  };
+
+
+/* The ui_out stream structure. */
+/* NOTE: cagney/2000-02-01: The ui_stream object can be subsumed by
+   the more generic ui_file object.  */
+
+struct ui_stream
+  {
+    struct ui_out *uiout;
+    struct ui_file *stream;
+  };
+
+
+/* Prototypes for ui-out API. */
+
+extern void ui_out_table_begin PARAMS ((struct ui_out * uiout, int nbrofcols,
+                                       char *tblid));
+
+extern void ui_out_table_header PARAMS ((struct ui_out * uiout, int width,
+                                        enum ui_align align, char *colhdr));
+
+extern void ui_out_table_body PARAMS ((struct ui_out * uiout));
+
+extern void ui_out_table_end PARAMS ((struct ui_out * uiout));
+
+extern void ui_out_list_begin PARAMS ((struct ui_out * uiout, char *lstid));
+
+extern void ui_out_list_end PARAMS ((struct ui_out * uiout));
+
+extern void ui_out_field_int PARAMS ((struct ui_out * uiout, char *fldname,
+                                     int value));
+
+extern void ui_out_field_core_addr PARAMS ((struct ui_out * uiout, char *fldname,
+                                           CORE_ADDR address));
+
+extern void ui_out_field_string (struct ui_out * uiout, char *fldname,
+                                const char *string);
+
+extern void ui_out_field_stream PARAMS ((struct ui_out * uiout, char *fldname,
+                                        struct ui_stream * buf));
+
+extern void ui_out_field_fmt PARAMS ((struct ui_out * uiout, char *fldname,
+                                     char *format,...));
+
+extern void ui_out_field_skip PARAMS ((struct ui_out * uiout, char *fldname));
+
+extern void ui_out_spaces PARAMS ((struct ui_out * uiout, int numspaces));
+
+extern void ui_out_text PARAMS ((struct ui_out * uiout, char *string));
+
+extern void ui_out_message PARAMS ((struct ui_out * uiout, int verbosity,
+                                   char *format,...));
+
+extern struct ui_stream *ui_out_stream_new PARAMS ((struct ui_out * uiout));
+
+extern void ui_out_stream_delete PARAMS ((struct ui_stream * buf));
+
+struct cleanup *make_cleanup_ui_out_stream_delete (struct ui_stream *buf);
+
+extern void ui_out_wrap_hint PARAMS ((struct ui_out * uiout, char *identstring));
+
+extern void ui_out_flush PARAMS ((struct ui_out * uiout));
+
+extern void ui_out_get_field_separator PARAMS ((struct ui_out * uiout));
+
+extern int ui_out_set_flags PARAMS ((struct ui_out * uiout, int mask));
+
+extern int ui_out_clear_flags PARAMS ((struct ui_out * uiout, int mask));
+
+extern int ui_out_get_verblvl PARAMS ((struct ui_out * uiout));
+
+extern int ui_out_test_flags (struct ui_out *uiout, int mask);
+
+#if 0
+extern void ui_out_result_begin PARAMS ((struct ui_out * uiout, char *class));
+
+extern void ui_out_result_end PARAMS ((struct ui_out * uiout));
+
+extern void ui_out_info_begin PARAMS ((struct ui_out * uiout, char *class));
+
+extern void ui_out_info_end PARAMS ((struct ui_out * uiout));
+
+extern void ui_out_notify_begin PARAMS ((struct ui_out * uiout, char *class));
+
+extern void ui_out_notify_end PARAMS ((struct ui_out * uiout));
+
+extern void ui_out_error_begin PARAMS ((struct ui_out * uiout, char *class));
+
+extern void ui_out_error_end PARAMS ((struct ui_out * uiout));
+#endif
+
+#if 0
+extern void gdb_error PARAMS ((struct ui_out * uiout, int severity,
+                              char *format,...));
+
+extern void gdb_query PARAMS ((struct ui_out * uiout,
+                              int qflags, char *qprompt));
+#endif
+
+/* From here on we have things that are only needed by implementation
+   routines and main.c.   We should pehaps have a separate file for that,
+   like a  ui-out-impl.h  file */
+
+/* User Interface Output Implementation Function Table */
+
+/* Type definition of all implementation functions. */
+
+typedef void (table_begin_ftype) (struct ui_out * uiout,
+                                 int nbrofcols, char *tblid);
+typedef void (table_body_ftype) (struct ui_out * uiout);
+typedef void (table_end_ftype) (struct ui_out * uiout);
+typedef void (table_header_ftype) (struct ui_out * uiout, int width,
+                                  enum ui_align align, char *colhdr);
+typedef void (list_begin_ftype) (struct ui_out * uiout,
+                                int list_flag, char *lstid);
+typedef void (list_end_ftype) (struct ui_out * uiout, int list_flag);
+typedef void (field_int_ftype) (struct ui_out * uiout, int fldno, int width,
+                            enum ui_align align, char *fldname, int value);
+typedef void (field_skip_ftype) (struct ui_out * uiout, int fldno, int width,
+                                enum ui_align align, char *fldname);
+typedef void (field_string_ftype) (struct ui_out * uiout, int fldno, int width,
+                                  enum ui_align align, char *fldname,
+                                  const char *string);
+typedef void (field_fmt_ftype) (struct ui_out * uiout, int fldno, int width,
+                               enum ui_align align, char *fldname,
+                               char *format, va_list args);
+typedef void (spaces_ftype) (struct ui_out * uiout, int numspaces);
+typedef void (text_ftype) (struct ui_out * uiout, char *string);
+typedef void (message_ftype) (struct ui_out * uiout, int verbosity,
+                             char *format, va_list args);
+typedef void (wrap_hint_ftype) (struct ui_out * uiout, char *identstring);
+typedef void (flush_ftype) (struct ui_out * uiout);
+
+/* ui-out-impl */
+
+/* IMPORTANT: If you change this structure, make sure to change the default
+   initialization in ui-out.c */
+
+struct ui_out_impl
+  {
+    table_begin_ftype *table_begin;
+    table_body_ftype *table_body;
+    table_end_ftype *table_end;
+    table_header_ftype *table_header;
+    list_begin_ftype *list_begin;
+    list_end_ftype *list_end;
+    field_int_ftype *field_int;
+    field_skip_ftype *field_skip;
+    field_string_ftype *field_string;
+    field_fmt_ftype *field_fmt;
+    spaces_ftype *spaces;
+    text_ftype *text;
+    message_ftype *message;
+    wrap_hint_ftype *wrap_hint;
+    flush_ftype *flush;
+  };
+
+extern struct ui_out_data *ui_out_data (struct ui_out *uiout);
+
+
+/* Create a ui_out object */
+
+extern struct ui_out *ui_out_new (struct ui_out_impl *impl,
+                                 struct ui_out_data *data,
+                                 int flags);
+
+#endif /* UI_OUT_H */
diff --git a/gdb/varobj.c b/gdb/varobj.c
new file mode 100644 (file)
index 0000000..f0740c6
--- /dev/null
@@ -0,0 +1,2421 @@
+/* Implementation of the GDB variable objects API.
+   Copyright 1999, 2000 Free Software Foundation, Inc.
+
+   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 "value.h"
+#include "expression.h"
+#include "frame.h"
+#include "valprint.h"
+#include "language.h"
+#include "wrapper.h"
+#include "gdbcmd.h"
+#include <math.h>
+
+#include "varobj.h"
+
+/* Non-zero if we want to see trace of varobj level stuff.  */
+
+int varobjdebug = 0;
+
+/* String representations of gdb's format codes */
+char *varobj_format_string[] =
+{"natural", "binary", "decimal", "hexadecimal", "octal"};
+
+/* String representations of gdb's known languages */
+char *varobj_language_string[] =
+{"unknown", "C", "C++", "Java"};
+
+/* Data structures */
+
+/* Every root variable has one of these structures saved in its
+   varobj. Members which must be free'd are noted. */
+struct varobj_root
+  {
+
+    /* Alloc'd expression for this parent. */
+    struct expression *exp;
+
+    /* Block for which this expression is valid */
+    struct block *valid_block;
+
+    /* The frame for this expression */
+    CORE_ADDR frame;
+
+    /* Language info for this variable and its children */
+    struct language_specific *lang;
+
+    /* The varobj for this root node. */
+    struct varobj *rootvar;
+
+    /* Next root variable */
+    struct varobj_root *next;
+  };
+
+/* Every variable in the system has a structure of this type defined
+   for it. This structure holds all information necessary to manipulate
+   a particular object variable. Members which must be freed are noted. */
+struct varobj
+  {
+
+    /* Alloc'd name of the variable for this object.. If this variable is a
+       child, then this name will be the child's source name.
+       (bar, not foo.bar) */
+    /* NOTE: This is the "expression" */
+    char *name;
+
+    /* The alloc'd name for this variable's object. This is here for
+       convenience when constructing this object's children. */
+    char *obj_name;
+
+    /* Index of this variable in its parent or -1 */
+    int index;
+
+    /* The type of this variable. This may NEVER be NULL. */
+    struct type *type;
+
+    /* The value of this expression or subexpression.  This may be NULL. */
+    value_ptr value;
+
+    /* Did an error occur evaluating the expression or getting its value? */
+    int error;
+
+    /* The number of (immediate) children this variable has */
+    int num_children;
+
+    /* If this object is a child, this points to its immediate parent. */
+    struct varobj *parent;
+
+    /* A list of this object's children */
+    struct varobj_child *children;
+
+    /* Description of the root variable. Points to root variable for children. */
+    struct varobj_root *root;
+
+    /* The format of the output for this object */
+    enum varobj_display_formats format;
+  };
+
+/* Every variable keeps a linked list of its children, described
+   by the following structure. */
+/* FIXME: Deprecated.  All should use vlist instead */
+
+struct varobj_child
+  {
+
+    /* Pointer to the child's data */
+    struct varobj *child;
+
+    /* Pointer to the next child */
+    struct varobj_child *next;
+  };
+
+/* A stack of varobjs */
+/* FIXME: Deprecated.  All should use vlist instead */
+
+struct vstack
+  {
+    struct varobj *var;
+    struct vstack *next;
+  };
+
+struct cpstack
+  {
+    char *name;
+    struct cpstack *next;
+  };
+
+/* A list of varobjs */
+
+struct vlist
+  {
+    struct varobj *var;
+    struct vlist *next;
+  };
+
+/* Private function prototypes */
+
+/* Helper functions for the above subcommands. */
+
+static int delete_variable PARAMS ((struct cpstack **, struct varobj *, int));
+
+static void delete_variable_1 PARAMS ((struct cpstack **, int *,
+                                      struct varobj *, int, int));
+
+static int install_variable PARAMS ((struct varobj *));
+
+static void uninstall_variable PARAMS ((struct varobj *));
+
+static struct varobj *child_exists PARAMS ((struct varobj *, char *));
+
+static struct varobj *create_child PARAMS ((struct varobj *, int, char *));
+
+static void save_child_in_parent PARAMS ((struct varobj *, struct varobj *));
+
+static void remove_child_from_parent PARAMS ((struct varobj *, struct varobj *));
+
+/* Utility routines */
+
+static struct varobj *new_variable PARAMS ((void));
+
+static struct varobj *new_root_variable PARAMS ((void));
+
+static void free_variable PARAMS ((struct varobj * var));
+
+static struct type *get_type PARAMS ((struct varobj * var));
+
+static struct type *get_type_deref PARAMS ((struct varobj * var));
+
+static struct type *get_target_type PARAMS ((struct type *));
+
+static enum varobj_display_formats variable_default_display PARAMS ((struct varobj *));
+
+static int my_value_equal PARAMS ((value_ptr, value_ptr, int *));
+
+static void vpush PARAMS ((struct vstack ** pstack, struct varobj * var));
+
+static struct varobj *vpop PARAMS ((struct vstack ** pstack));
+
+static void cppush PARAMS ((struct cpstack ** pstack, char *name));
+
+static char *cppop PARAMS ((struct cpstack ** pstack));
+
+/* Language-specific routines. */
+
+static enum varobj_languages variable_language PARAMS ((struct varobj * var));
+
+static int number_of_children PARAMS ((struct varobj *));
+
+static char *name_of_variable PARAMS ((struct varobj *));
+
+static char *name_of_child PARAMS ((struct varobj *, int));
+
+static value_ptr value_of_root PARAMS ((struct varobj * var));
+
+static value_ptr value_of_child PARAMS ((struct varobj * parent, int index));
+
+static struct type *type_of_child PARAMS ((struct varobj * var));
+
+static int variable_editable PARAMS ((struct varobj * var));
+
+static char *my_value_of_variable PARAMS ((struct varobj * var));
+
+static int type_changeable PARAMS ((struct varobj * var));
+
+/* C implementation */
+
+static int c_number_of_children PARAMS ((struct varobj * var));
+
+static char *c_name_of_variable PARAMS ((struct varobj * parent));
+
+static char *c_name_of_child PARAMS ((struct varobj * parent, int index));
+
+static value_ptr c_value_of_root PARAMS ((struct varobj * var));
+
+static value_ptr c_value_of_child PARAMS ((struct varobj * parent, int index));
+
+static struct type *c_type_of_child PARAMS ((struct varobj * parent, int index));
+
+static int c_variable_editable PARAMS ((struct varobj * var));
+
+static char *c_value_of_variable PARAMS ((struct varobj * var));
+
+/* C++ implementation */
+
+static int cplus_number_of_children PARAMS ((struct varobj * var));
+
+static void cplus_class_num_children PARAMS ((struct type * type, int children[3]));
+
+static char *cplus_name_of_variable PARAMS ((struct varobj * parent));
+
+static char *cplus_name_of_child PARAMS ((struct varobj * parent, int index));
+
+static value_ptr cplus_value_of_root PARAMS ((struct varobj * var));
+
+static value_ptr cplus_value_of_child PARAMS ((struct varobj * parent, int index));
+
+static struct type *cplus_type_of_child PARAMS ((struct varobj * parent, int index));
+
+static int cplus_variable_editable PARAMS ((struct varobj * var));
+
+static char *cplus_value_of_variable PARAMS ((struct varobj * var));
+
+/* Java implementation */
+
+static int java_number_of_children PARAMS ((struct varobj * var));
+
+static char *java_name_of_variable PARAMS ((struct varobj * parent));
+
+static char *java_name_of_child PARAMS ((struct varobj * parent, int index));
+
+static value_ptr java_value_of_root PARAMS ((struct varobj * var));
+
+static value_ptr java_value_of_child PARAMS ((struct varobj * parent, int index));
+
+static struct type *java_type_of_child PARAMS ((struct varobj * parent, int index));
+
+static int java_variable_editable PARAMS ((struct varobj * var));
+
+static char *java_value_of_variable PARAMS ((struct varobj * var));
+
+/* The language specific vector */
+
+struct language_specific
+  {
+
+    /* The language of this variable */
+    enum varobj_languages language;
+
+    /* The number of children of PARENT. */
+    int (*number_of_children) PARAMS ((struct varobj * parent));
+
+    /* The name (expression) of a root varobj. */
+    char *(*name_of_variable) PARAMS ((struct varobj * parent));
+
+    /* The name of the INDEX'th child of PARENT. */
+    char *(*name_of_child) PARAMS ((struct varobj * parent, int index));
+
+    /* The value_ptr of the root variable ROOT. */
+      value_ptr (*value_of_root) PARAMS ((struct varobj * root));
+
+    /* The value_ptr of the INDEX'th child of PARENT. */
+      value_ptr (*value_of_child) PARAMS ((struct varobj * parent, int index));
+
+    /* The type of the INDEX'th child of PARENT. */
+    struct type *(*type_of_child) PARAMS ((struct varobj * parent, int index));
+
+    /* Is VAR editable? */
+    int (*variable_editable) PARAMS ((struct varobj * var));
+
+    /* The current value of VAR. */
+    char *(*value_of_variable) PARAMS ((struct varobj * var));
+  };
+
+/* Array of known source language routines. */
+static struct language_specific
+  languages[vlang_end][sizeof (struct language_specific)] =
+{
+  /* Unknown (try treating as C */
+  {
+    vlang_unknown,
+      c_number_of_children,
+      c_name_of_variable,
+      c_name_of_child,
+      c_value_of_root,
+      c_value_of_child,
+      c_type_of_child,
+      c_variable_editable,
+      c_value_of_variable
+  }
+  ,
+  /* C */
+  {
+    vlang_c,
+      c_number_of_children,
+      c_name_of_variable,
+      c_name_of_child,
+      c_value_of_root,
+      c_value_of_child,
+      c_type_of_child,
+      c_variable_editable,
+      c_value_of_variable
+  }
+  ,
+  /* C++ */
+  {
+    vlang_cplus,
+      cplus_number_of_children,
+      cplus_name_of_variable,
+      cplus_name_of_child,
+      cplus_value_of_root,
+      cplus_value_of_child,
+      cplus_type_of_child,
+      cplus_variable_editable,
+      cplus_value_of_variable
+  }
+  ,
+  /* Java */
+  {
+    vlang_java,
+      java_number_of_children,
+      java_name_of_variable,
+      java_name_of_child,
+      java_value_of_root,
+      java_value_of_child,
+      java_type_of_child,
+      java_variable_editable,
+      java_value_of_variable
+  }
+};
+
+/* A little convenience enum for dealing with C++/Java */
+enum vsections
+  {
+    v_public = 0, v_private, v_protected
+  };
+
+/* Private data */
+
+/* Mappings of varobj_display_formats enums to gdb's format codes */
+static int format_code[] =
+{0, 't', 'd', 'x', 'o'};
+
+/* Header of the list of root variable objects */
+static struct varobj_root *rootlist;
+static int rootcount = 0;      /* number of root varobjs in the list */
+
+/* Prime number indicating the number of buckets in the hash table */
+/* A prime large enough to avoid too many colisions */
+#define VAROBJ_TABLE_SIZE 227
+
+/* Pointer to the varobj hash table (built at run time) */
+static struct vlist **varobj_table;
+
+#if defined(FREEIF)
+#undef FREEIF
+#endif
+#define FREEIF(x) if (x != NULL) free((char *) (x))
+
+/* Is the variable X one of our "fake" children? */
+#define CPLUS_FAKE_CHILD(x) \
+((x) != NULL && (x)->type == NULL && (x)->value == NULL)
+\f
+
+/* API Implementation */
+
+/* Creates a varobj (not its children) */
+
+struct varobj *
+varobj_create (char *objname,
+              char *expression, CORE_ADDR frame)
+{
+  struct varobj *var;
+  struct frame_info *fi, *old_fi;
+  struct block *block;
+  struct cleanup *old_chain;
+
+  /* Fill out a varobj structure for the (root) variable being constructed. */
+  var = new_root_variable ();
+  old_chain = make_cleanup ((make_cleanup_func) free_variable, var);
+
+  if (expression != NULL)
+    {
+      char *p;
+      enum varobj_languages lang;
+
+      /* Parse and evaluate the expression, filling in as much
+         of the variable's data as possible */
+
+      /* Allow creator to specify context of variable */
+      if (frame == (CORE_ADDR) -1)
+       fi = selected_frame;
+      else
+       fi = find_frame_addr_in_frame_chain (frame);
+
+      block = NULL;
+      if (fi != NULL)
+       block = get_frame_block (fi);
+
+      p = expression;
+      innermost_block = NULL;
+      /* Callee may longjump */
+      var->root->exp = parse_exp_1 (&p, block, 0);
+
+      /* Don't allow variables to be created for types. */
+      if (var->root->exp->elts[0].opcode == OP_TYPE)
+       {
+         do_cleanups (old_chain);
+         fprintf_unfiltered (gdb_stderr,
+                           "Attempt to use a type name as an expression.");
+         return NULL;
+       }
+
+      var->format = variable_default_display (var);
+      var->root->valid_block = innermost_block;
+      var->name = savestring (expression, strlen (expression));
+
+      /* When the frame is different from the current frame, 
+         we must select the appropriate frame before parsing
+         the expression, otherwise the value will not be current.
+         Since select_frame is so benign, just call it for all cases. */
+      if (fi != NULL)
+       {
+         var->root->frame = FRAME_FP (fi);
+         old_fi = selected_frame;
+         select_frame (fi, -1);
+       }
+
+      /* We definitively need to catch errors here.
+         If evaluate_expression succeeds we got the value we wanted.
+         But if it fails, we still go on with a call to evaluate_type()  */
+      if (gdb_evaluate_expression (var->root->exp, &var->value))
+       {
+         /* no error */
+         release_value (var->value);
+         if (VALUE_LAZY (var->value))
+           gdb_value_fetch_lazy (var->value);
+       }
+      else
+       var->value = evaluate_type (var->root->exp);
+
+      var->type = VALUE_TYPE (var->value);
+
+      /* Set language info */
+      lang = variable_language (var);
+      var->root->lang = languages[lang];
+
+      /* Set ourselves as our root */
+      var->root->rootvar = var;
+
+      /* Reset the selected frame */
+      if (fi != NULL)
+       select_frame (old_fi, -1);
+    }
+
+  if (var != NULL)
+    {
+      var->obj_name = savestring (objname, strlen (objname));
+
+      /* If a varobj name is duplicated, the install will fail so
+         we must clenup */
+      if (!install_variable (var))
+       {
+         do_cleanups (old_chain);
+         return NULL;
+       }
+    }
+
+  discard_cleanups (old_chain);
+  return var;
+}
+
+/* Generates an unique name that can be used for a varobj */
+
+char *
+varobj_gen_name (void)
+{
+  static int id = 0;
+  char obj_name[31];
+
+  /* generate a name for this object */
+  id++;
+  sprintf (obj_name, "var%d", id);
+
+  return xstrdup (obj_name);
+}
+
+/* Given an "objname", returns the pointer to the corresponding varobj
+   or NULL if not found */
+
+struct varobj *
+varobj_get_handle (char *objname)
+{
+  struct vlist *cv;
+  const char *chp;
+  unsigned int index = 0;
+  unsigned int i = 1;
+
+  for (chp = objname; *chp; chp++)
+    {
+      index = (index + (i++ * (unsigned int) *chp)) % VAROBJ_TABLE_SIZE;
+    }
+
+  cv = *(varobj_table + index);
+  while ((cv != NULL) && (strcmp (cv->var->obj_name, objname) != 0))
+    cv = cv->next;
+
+  if (cv == NULL)
+    error ("Variable object not found");
+
+  return cv->var;
+}
+
+/* Given the handle, return the name of the object */
+
+char *
+varobj_get_objname (struct varobj *var)
+{
+  return var->obj_name;
+}
+
+/* Given the handle, return the expression represented by the object */
+
+char *
+varobj_get_expression (struct varobj *var)
+{
+  return name_of_variable (var);
+}
+
+/* Deletes a varobj and all its children if only_children == 0,
+   otherwise deletes only the children; returns a malloc'ed list of all the 
+   (malloc'ed) names of the variables that have been deleted (NULL terminated) */
+
+int
+varobj_delete (struct varobj *var, char ***dellist, int only_children)
+{
+  int delcount;
+  int mycount;
+  struct cpstack *result = NULL;
+  char **cp;
+
+  /* Initialize a stack for temporary results */
+  cppush (&result, NULL);
+
+  if (only_children)
+    /* Delete only the variable children */
+    delcount = delete_variable (&result, var, 1 /* only the children */ );
+  else
+    /* Delete the variable and all its children */
+    delcount = delete_variable (&result, var, 0 /* parent+children */ );
+
+  /* We may have been asked to return a list of what has been deleted */
+  if (dellist != NULL)
+    {
+      *dellist = xmalloc ((delcount + 1) * sizeof (char *));
+
+      cp = *dellist;
+      mycount = delcount;
+      *cp = cppop (&result);
+      while ((*cp != NULL) && (mycount > 0))
+       {
+         mycount--;
+         cp++;
+         *cp = cppop (&result);
+       }
+
+      if (mycount || (*cp != NULL))
+       warning ("varobj_delete: assertion failed - mycount(=%d) <> 0", mycount);
+    }
+
+  return delcount;
+}
+
+/* Set/Get variable object display format */
+
+enum varobj_display_formats
+varobj_set_display_format (struct varobj *var,
+                          enum varobj_display_formats format)
+{
+  switch (format)
+    {
+    case FORMAT_NATURAL:
+    case FORMAT_BINARY:
+    case FORMAT_DECIMAL:
+    case FORMAT_HEXADECIMAL:
+    case FORMAT_OCTAL:
+      var->format = format;
+      break;
+
+    default:
+      var->format = variable_default_display (var);
+    }
+
+  return var->format;
+}
+
+enum varobj_display_formats
+varobj_get_display_format (struct varobj *var)
+{
+  return var->format;
+}
+
+int
+varobj_get_num_children (struct varobj *var)
+{
+  if (var->num_children == -1)
+    var->num_children = number_of_children (var);
+
+  return var->num_children;
+}
+
+/* Creates a list of the immediate children of a variable object;
+   the return code is the number of such children or -1 on error */
+
+int
+varobj_list_children (struct varobj *var, struct varobj ***childlist)
+{
+  struct varobj *child;
+  char *name;
+  int i;
+
+  /* sanity check: have we been passed a pointer? */
+  if (childlist == NULL)
+    return -1;
+
+  *childlist = NULL;
+
+  if (var->num_children == -1)
+    var->num_children = number_of_children (var);
+
+  /* List of children */
+  *childlist = xmalloc ((var->num_children + 1) * sizeof (struct varobj *));
+
+  for (i = 0; i < var->num_children; i++)
+    {
+      /* Mark as the end in case we bail out */
+      *((*childlist) + i) = NULL;
+
+      /* check if child exists, if not create */
+      name = name_of_child (var, i);
+      child = child_exists (var, name);
+      if (child == NULL)
+       child = create_child (var, i, name);
+
+      *((*childlist) + i) = child;
+    }
+
+  /* End of list is marked by a NULL pointer */
+  *((*childlist) + i) = NULL;
+
+  return var->num_children;
+}
+
+/* Obtain the type of an object Variable as a string similar to the one gdb
+   prints on the console */
+
+char *
+varobj_get_type (struct varobj *var)
+{
+  value_ptr val;
+  struct cleanup *old_chain;
+  struct ui_file *stb;
+  char *thetype;
+  long length;
+
+  /* For the "fake" variables, do not return a type. (It's type is
+     NULL, too.) */
+  if (CPLUS_FAKE_CHILD (var))
+    return NULL;
+
+  stb = mem_fileopen ();
+  old_chain = make_cleanup_ui_file_delete (stb);
+
+  /* To print the type, we simply create a zero value_ptr and
+     cast it to our type. We then typeprint this variable. */
+  val = value_zero (var->type, not_lval);
+  type_print (VALUE_TYPE (val), "", stb, -1);
+
+  thetype = ui_file_xstrdup (stb, &length);
+  do_cleanups (old_chain);
+  return thetype;
+}
+
+enum varobj_languages
+varobj_get_language (struct varobj *var)
+{
+  return variable_language (var);
+}
+
+int
+varobj_get_attributes (struct varobj *var)
+{
+  int attributes = 0;
+
+  if (variable_editable (var))
+    /* FIXME: define masks for attributes */
+    attributes |= 0x00000001;  /* Editable */
+
+  return attributes;
+}
+
+char *
+varobj_get_value (struct varobj *var)
+{
+  return my_value_of_variable (var);
+}
+
+/* Set the value of an object variable (if it is editable) to the
+   value of the given expression */
+/* Note: Invokes functions that can call error() */
+
+int
+varobj_set_value (struct varobj *var, char *expression)
+{
+  value_ptr val;
+  int offset = 0;
+
+  /* The argument "expression" contains the variable's new value.
+     We need to first construct a legal expression for this -- ugh! */
+  /* Does this cover all the bases? */
+  struct expression *exp;
+  value_ptr value;
+  int saved_input_radix = input_radix;
+
+  if (variable_editable (var) && !var->error)
+    {
+      char *s = expression;
+      int i;
+      value_ptr temp;
+
+      input_radix = 10;                /* ALWAYS reset to decimal temporarily */
+      /* FIXME: Callee may longjump */
+      exp = parse_exp_1 (&s, 0, 0);
+      if (!gdb_evaluate_expression (exp, &value))
+       {
+         /* We cannot proceed without a valid expression. */
+         FREEIF (exp);
+         return 0;
+       }
+
+      /* If our parent is "public", "private", or "protected", we could
+         be asking to modify the value of a baseclass. If so, we need to
+         adjust our address by the offset of our baseclass in the subclass,
+         since VALUE_ADDRESS (var->value) points at the start of the subclass.
+         For some reason, value_cast doesn't take care of this properly. */
+      temp = var->value;
+      if (var->parent != NULL && CPLUS_FAKE_CHILD (var->parent))
+       {
+         struct varobj *super, *sub;
+         struct type *type;
+         super = var->parent->parent;
+         sub = super->parent;
+         if (sub != NULL)
+           {
+             /* Yes, it is a baseclass */
+             type = get_type_deref (sub);
+
+             if (super->index < TYPE_N_BASECLASSES (type))
+               {
+                 temp = value_copy (var->value);
+                 for (i = 0; i < super->index; i++)
+                   offset += TYPE_LENGTH (TYPE_FIELD_TYPE (type, i));
+               }
+           }
+       }
+
+      VALUE_ADDRESS (temp) += offset;
+      val = value_assign (temp, value);
+      VALUE_ADDRESS (val) -= offset;
+      value_free (var->value);
+      release_value (val);
+      var->value = val;
+      input_radix = saved_input_radix;
+      return 1;
+    }
+
+  return 0;
+}
+
+/* Returns a malloc'ed list with all root variable objects */
+int
+varobj_list (struct varobj ***varlist)
+{
+  struct varobj **cv;
+  struct varobj_root *croot;
+  int mycount = rootcount;
+
+  /* Alloc (rootcount + 1) entries for the result */
+  *varlist = xmalloc ((rootcount + 1) * sizeof (struct varobj *));
+
+  cv = *varlist;
+  croot = rootlist;
+  while ((croot != NULL) && (mycount > 0))
+    {
+      *cv = croot->rootvar;
+      mycount--;
+      cv++;
+      croot = croot->next;
+    }
+  /* Mark the end of the list */
+  *cv = NULL;
+
+  if (mycount || (croot != NULL))
+    warning ("varobj_list: assertion failed - wrong tally of root vars (%d:%d)",
+            rootcount, mycount);
+
+  return rootcount;
+}
+
+/* Update the values for a variable and its children.  This is a
+   two-pronged attack.  First, re-parse the value for the root's
+   expression to see if it's changed.  Then go all the way
+   through its children, reconstructing them and noting if they've
+   changed.
+
+   Only root variables can be updated... */
+
+int
+varobj_update (struct varobj *var, struct varobj ***changelist)
+{
+  int changed = 0;
+  int i;
+  int vleft;
+  int error2;
+  struct varobj *v;
+  struct varobj **cv;
+  struct varobj **templist;
+  value_ptr new;
+  struct vstack *stack = NULL;
+  struct vstack *result = NULL;
+  struct frame_info *old_fi;
+
+  /* sanity check: have we been passed a pointer? */
+  if (changelist == NULL)
+    return -1;
+
+  /*  Only root variables can be updated... */
+  if (var->root->rootvar != var)
+    /* Not a root var */
+    return -1;
+
+  /* Save the selected stack frame, since we will need to change it
+     in order to evaluate expressions. */
+  old_fi = selected_frame;
+
+  /* Update the root variable. value_of_root can return NULL
+     if the variable is no longer around, i.e. we stepped out of
+     the frame in which a local existed. */
+  new = value_of_root (var);
+  if (new == NULL)
+    return -1;
+
+  /* Initialize a stack for temporary results */
+  vpush (&result, NULL);
+
+  if (!my_value_equal (var->value, new, &error2))
+    {
+      /* Note that it's changed   There a couple of exceptions here,
+         though. We don't want some types to be reported as "changed". */
+      if (type_changeable (var))
+       {
+         vpush (&result, var);
+         changed++;
+       }
+    }
+  /* error2 replaces var->error since this new value
+     WILL replace the old one. */
+  var->error = error2;
+
+  /* We must always keep around the new value for this root
+     variable expression, or we lose the updated children! */
+  value_free (var->value);
+  var->value = new;
+
+  /* Initialize a stack */
+  vpush (&stack, NULL);
+
+  /* Push the root's children */
+  if (var->children != NULL)
+    {
+      struct varobj_child *c;
+      for (c = var->children; c != NULL; c = c->next)
+       vpush (&stack, c->child);
+    }
+
+  /* Walk through the children, reconstructing them all. */
+  v = vpop (&stack);
+  while (v != NULL)
+    {
+      /* Push any children */
+      if (v->children != NULL)
+       {
+         struct varobj_child *c;
+         for (c = v->children; c != NULL; c = c->next)
+           vpush (&stack, c->child);
+       }
+
+      /* Update this variable */
+      new = value_of_child (v->parent, v->index);
+      if (type_changeable (v) && !my_value_equal (v->value, new, &error2))
+       {
+         /* Note that it's changed */
+         vpush (&result, v);
+         changed++;
+       }
+      /* error2 replaces v->error since this new value
+         WILL replace the old one. */
+      v->error = error2;
+
+      /* We must always keep new values, since children depend on it. */
+      if (v->value != NULL)
+       value_free (v->value);
+      v->value = new;
+
+      /* Get next child */
+      v = vpop (&stack);
+    }
+
+  /* Alloc (changed + 1) list entries */
+  /* FIXME: add a cleanup for the allocated list(s)
+     because one day the select_frame called below can longjump */
+  *changelist = xmalloc ((changed + 1) * sizeof (struct varobj *));
+  if (changed > 1)
+    {
+      templist = xmalloc ((changed + 1) * sizeof (struct varobj *));
+      cv = templist;
+    }
+  else
+    cv = *changelist;
+
+  /* Copy from result stack to list */
+  vleft = changed;
+  *cv = vpop (&result);
+  while ((*cv != NULL) && (vleft > 0))
+    {
+      vleft--;
+      cv++;
+      *cv = vpop (&result);
+    }
+  if (vleft)
+    warning ("varobj_update: assertion failed - vleft <> 0");
+
+  if (changed > 1)
+    {
+      /* Now we revert the order. */
+      for (i=0; i < changed; i++)
+        *(*changelist + i) = *(templist + changed -1 - i);
+      *(*changelist + changed) = NULL;
+    }
+
+  /* Restore selected frame */
+  select_frame (old_fi, -1);
+
+  return changed;
+}
+\f
+
+/* Helper functions */
+
+/*
+ * Variable object construction/destruction
+ */
+
+static int
+delete_variable (resultp, var, only_children_p)
+     struct cpstack **resultp;
+     struct varobj *var;
+     int only_children_p;
+{
+  int delcount = 0;
+
+  delete_variable_1 (resultp, &delcount, var,
+                    only_children_p, 1 /* remove_from_parent_p */ );
+
+  return delcount;
+}
+
+/* Delete the variable object VAR and its children */
+/* IMPORTANT NOTE: If we delete a variable which is a child
+   and the parent is not removed we dump core.  It must be always
+   initially called with remove_from_parent_p set */
+static void
+delete_variable_1 (resultp, delcountp, var,
+                  only_children_p, remove_from_parent_p)
+     struct cpstack **resultp;
+     int *delcountp;
+     struct varobj *var;
+     int only_children_p;
+     int remove_from_parent_p;
+{
+  struct varobj_child *vc;
+  struct varobj_child *next;
+
+  /* Delete any children of this variable, too. */
+  for (vc = var->children; vc != NULL; vc = next)
+    {
+      if (!remove_from_parent_p)
+       vc->child->parent = NULL;
+      delete_variable_1 (resultp, delcountp, vc->child, 0, only_children_p);
+      next = vc->next;
+      free (vc);
+    }
+
+  /* if we were called to delete only the children we are done here */
+  if (only_children_p)
+    return;
+
+  /* Otherwise, add it to the list of deleted ones and proceed to do so */
+  if (var->obj_name == NULL)
+    warning ("Assertion failed: NULL var->obj_name unexpectdly found");
+  else
+    {
+      cppush (resultp, strdup (var->obj_name));
+      *delcountp = *delcountp + 1;
+    }
+
+  /* If this variable has a parent, remove it from its parent's list */
+  /* OPTIMIZATION: if the parent of this variable is also being deleted, 
+     (as indicated by remove_from_parent_p) we don't bother doing an
+     expensive list search to find the element to remove when we are
+     discarding the list afterwards */
+  if ((remove_from_parent_p) &&
+      (var->parent != NULL))
+    {
+      remove_child_from_parent (var->parent, var);
+    }
+
+  uninstall_variable (var);
+
+  /* Free memory associated with this variable */
+  free_variable (var);
+}
+
+/* Install the given variable VAR with the object name VAR->OBJ_NAME. */
+static int
+install_variable (var)
+     struct varobj *var;
+{
+  struct vlist *cv;
+  struct vlist *newvl;
+  const char *chp;
+  unsigned int index = 0;
+  unsigned int i = 1;
+
+  for (chp = var->obj_name; *chp; chp++)
+    {
+      index = (index + (i++ * (unsigned int) *chp)) % VAROBJ_TABLE_SIZE;
+    }
+
+  cv = *(varobj_table + index);
+  while ((cv != NULL) && (strcmp (cv->var->obj_name, var->obj_name) != 0))
+    cv = cv->next;
+
+  if (cv != NULL)
+    error ("Duplicate variable object name");
+
+  /* Add varobj to hash table */
+  newvl = xmalloc (sizeof (struct vlist));
+  newvl->next = *(varobj_table + index);
+  newvl->var = var;
+  *(varobj_table + index) = newvl;
+
+  /* If root, add varobj to root list */
+  if (var->root->rootvar == var)
+    {
+      /* Add to list of root variables */
+      if (rootlist == NULL)
+       var->root->next = NULL;
+      else
+       var->root->next = rootlist;
+      rootlist = var->root;
+      rootcount++;
+    }
+
+  return 1;                    /* OK */
+}
+
+/* Unistall the object VAR. */
+static void
+uninstall_variable (var)
+     struct varobj *var;
+{
+  struct vlist *cv;
+  struct vlist *prev;
+  struct varobj_root *cr;
+  struct varobj_root *prer;
+  const char *chp;
+  unsigned int index = 0;
+  unsigned int i = 1;
+
+  /* Remove varobj from hash table */
+  for (chp = var->obj_name; *chp; chp++)
+    {
+      index = (index + (i++ * (unsigned int) *chp)) % VAROBJ_TABLE_SIZE;
+    }
+
+  cv = *(varobj_table + index);
+  prev = NULL;
+  while ((cv != NULL) && (strcmp (cv->var->obj_name, var->obj_name) != 0))
+    {
+      prev = cv;
+      cv = cv->next;
+    }
+
+  if (varobjdebug)
+    fprintf_unfiltered (gdb_stdlog, "Deleting %s\n", var->obj_name);
+
+  if (cv == NULL)
+    {
+      warning ("Assertion failed: Could not find variable object \"%s\" to delete", var->obj_name);
+      return;
+    }
+
+  if (prev == NULL)
+    *(varobj_table + index) = cv->next;
+  else
+    prev->next = cv->next;
+
+  free (cv);
+
+  /* If root, remove varobj from root list */
+  if (var->root->rootvar == var)
+    {
+      /* Remove from list of root variables */
+      if (rootlist == var->root)
+       rootlist = var->root->next;
+      else
+       {
+         prer = NULL;
+         cr = rootlist;
+         while ((cr != NULL) && (cr->rootvar != var))
+           {
+             prer = cr;
+             cr = cr->next;
+           }
+         if (cr == NULL)
+           {
+             warning ("Assertion failed: Could not find varobj \"%s\" in root list", var->obj_name);
+             return;
+           }
+         if (prer == NULL)
+           rootlist = NULL;
+         else
+           prer->next = cr->next;
+       }
+      rootcount--;
+    }
+
+}
+
+/* Does a child with the name NAME exist in VAR? If so, return its data.
+   If not, return NULL. */
+static struct varobj *
+child_exists (var, name)
+     struct varobj *var;       /* Parent */
+     char *name;               /* name of child */
+{
+  struct varobj_child *vc;
+
+  for (vc = var->children; vc != NULL; vc = vc->next)
+    {
+      if (STREQ (vc->child->name, name))
+       return vc->child;
+    }
+
+  return NULL;
+}
+
+/* Create and install a child of the parent of the given name */
+static struct varobj *
+create_child (parent, index, name)
+     struct varobj *parent;
+     int index;
+     char *name;
+{
+  struct varobj *child;
+  char *childs_name;
+
+  child = new_variable ();
+
+  /* name is allocated by name_of_child */
+  child->name = name;
+  child->index = index;
+  child->value = value_of_child (parent, index);
+  if (child->value == NULL || parent->error)
+    child->error = 1;
+  child->parent = parent;
+  child->root = parent->root;
+  childs_name = (char *) xmalloc ((strlen (parent->obj_name) + strlen (name) + 2)
+                                 * sizeof (char));
+  sprintf (childs_name, "%s.%s", parent->obj_name, name);
+  child->obj_name = childs_name;
+  install_variable (child);
+
+  /* Save a pointer to this child in the parent */
+  save_child_in_parent (parent, child);
+
+  /* Note the type of this child */
+  child->type = type_of_child (child);
+
+  return child;
+}
+
+/* FIXME: This should be a generic add to list */
+/* Save CHILD in the PARENT's data. */
+static void
+save_child_in_parent (parent, child)
+     struct varobj *parent;
+     struct varobj *child;
+{
+  struct varobj_child *vc;
+
+  /* Insert the child at the top */
+  vc = parent->children;
+  parent->children =
+    (struct varobj_child *) xmalloc (sizeof (struct varobj_child));
+
+  parent->children->next = vc;
+  parent->children->child = child;
+}
+
+/* FIXME: This should be a generic remove from list */
+/* Remove the CHILD from the PARENT's list of children. */
+static void
+remove_child_from_parent (parent, child)
+     struct varobj *parent;
+     struct varobj *child;
+{
+  struct varobj_child *vc, *prev;
+
+  /* Find the child in the parent's list */
+  prev = NULL;
+  for (vc = parent->children; vc != NULL;)
+    {
+      if (vc->child == child)
+       break;
+      prev = vc;
+      vc = vc->next;
+    }
+
+  if (prev == NULL)
+    parent->children = vc->next;
+  else
+    prev->next = vc->next;
+
+}
+\f
+
+/*
+ * Miscellaneous utility functions.
+ */
+
+/* Allocate memory and initialize a new variable */
+static struct varobj *
+new_variable (void)
+{
+  struct varobj *var;
+
+  var = (struct varobj *) xmalloc (sizeof (struct varobj));
+  var->name = NULL;
+  var->obj_name = NULL;
+  var->index = -1;
+  var->type = NULL;
+  var->value = NULL;
+  var->error = 0;
+  var->num_children = -1;
+  var->parent = NULL;
+  var->children = NULL;
+  var->format = 0;
+  var->root = NULL;
+
+  return var;
+}
+
+/* Allocate memory and initialize a new root variable */
+static struct varobj *
+new_root_variable (void)
+{
+  struct varobj *var = new_variable ();
+  var->root = (struct varobj_root *) xmalloc (sizeof (struct varobj_root));;
+  var->root->lang = NULL;
+  var->root->exp = NULL;
+  var->root->valid_block = NULL;
+  var->root->frame = (CORE_ADDR) -1;
+  var->root->rootvar = NULL;
+
+  return var;
+}
+
+/* Free any allocated memory associated with VAR. */
+static void
+free_variable (var)
+     struct varobj *var;
+{
+  /* Free the expression if this is a root variable. */
+  if (var->root->rootvar == var)
+    {
+      free_current_contents ((char **) &var->root->exp);
+      FREEIF (var->root);
+    }
+
+  FREEIF (var->name);
+  FREEIF (var->obj_name);
+  FREEIF (var);
+}
+
+/* This returns the type of the variable. This skips past typedefs
+   and returns the real type of the variable. It also dereferences
+   pointers and references. */
+static struct type *
+get_type (var)
+     struct varobj *var;
+{
+  struct type *type;
+  type = var->type;
+
+  while (type != NULL && TYPE_CODE (type) == TYPE_CODE_TYPEDEF)
+    type = TYPE_TARGET_TYPE (type);
+
+  return type;
+}
+
+/* This returns the type of the variable, dereferencing pointers, too. */
+static struct type *
+get_type_deref (var)
+     struct varobj *var;
+{
+  struct type *type;
+
+  type = get_type (var);
+
+  if (type != NULL && (TYPE_CODE (type) == TYPE_CODE_PTR
+                      || TYPE_CODE (type) == TYPE_CODE_REF))
+    type = get_target_type (type);
+
+  return type;
+}
+
+/* This returns the target type (or NULL) of TYPE, also skipping
+   past typedefs, just like get_type (). */
+static struct type *
+get_target_type (type)
+     struct type *type;
+{
+  if (type != NULL)
+    {
+      type = TYPE_TARGET_TYPE (type);
+      while (type != NULL && TYPE_CODE (type) == TYPE_CODE_TYPEDEF)
+       type = TYPE_TARGET_TYPE (type);
+    }
+
+  return type;
+}
+
+/* What is the default display for this variable? We assume that
+   everything is "natural". Any exceptions? */
+static enum varobj_display_formats
+variable_default_display (var)
+     struct varobj *var;
+{
+  return FORMAT_NATURAL;
+}
+
+/* This function is similar to gdb's value_equal, except that this
+   one is "safe" -- it NEVER longjmps. It determines if the VAR's
+   value is the same as VAL2. */
+static int
+my_value_equal (val1, val2, error2)
+     value_ptr val1;
+     value_ptr val2;
+     int *error2;
+{
+  int r, err1, err2;
+
+  *error2 = 0;
+  /* Special case: NULL values. If both are null, say
+     they're equal. */
+  if (val1 == NULL && val2 == NULL)
+    return 1;
+  else if (val1 == NULL || val2 == NULL)
+    return 0;
+
+  /* This is bogus, but unfortunately necessary. We must know
+     exactly what caused an error -- reading val1 or val2 --  so
+     that we can really determine if we think that something has changed. */
+  err1 = 0;
+  err2 = 0;
+  /* We do need to catch errors here because the whole purpose
+     is to test if value_equal() has errored */
+  if (!gdb_value_equal (val1, val1, &r))
+    err1 = 1;
+
+  if (!gdb_value_equal (val2, val2, &r))
+    *error2 = err2 = 1;
+
+  if (err1 != err2)
+    return 0;
+
+  if (!gdb_value_equal (val1, val2, &r))
+    {
+      /* An error occurred, this could have happened if
+         either val1 or val2 errored. ERR1 and ERR2 tell
+         us which of these it is. If both errored, then
+         we assume nothing has changed. If one of them is
+         valid, though, then something has changed. */
+      if (err1 == err2)
+       {
+         /* both the old and new values caused errors, so
+            we say the value did not change */
+         /* This is indeterminate, though. Perhaps we should
+            be safe and say, yes, it changed anyway?? */
+         return 1;
+       }
+      else
+       {
+         return 0;
+       }
+    }
+
+  return r;
+}
+
+/* FIXME: The following should be generic for any pointer */
+static void
+vpush (pstack, var)
+     struct vstack **pstack;
+     struct varobj *var;
+{
+  struct vstack *s;
+
+  s = (struct vstack *) xmalloc (sizeof (struct vstack));
+  s->var = var;
+  s->next = *pstack;
+  *pstack = s;
+}
+
+/* FIXME: The following should be generic for any pointer */
+static struct varobj *
+vpop (pstack)
+     struct vstack **pstack;
+{
+  struct vstack *s;
+  struct varobj *v;
+
+  if ((*pstack)->var == NULL && (*pstack)->next == NULL)
+    return NULL;
+
+  s = *pstack;
+  v = s->var;
+  *pstack = (*pstack)->next;
+  free (s);
+
+  return v;
+}
+
+/* FIXME: The following should be generic for any pointer */
+static void
+cppush (pstack, name)
+     struct cpstack **pstack;
+     char *name;
+{
+  struct cpstack *s;
+
+  s = (struct cpstack *) xmalloc (sizeof (struct cpstack));
+  s->name = name;
+  s->next = *pstack;
+  *pstack = s;
+}
+
+/* FIXME: The following should be generic for any pointer */
+static char *
+cppop (pstack)
+     struct cpstack **pstack;
+{
+  struct cpstack *s;
+  char *v;
+
+  if ((*pstack)->name == NULL && (*pstack)->next == NULL)
+    return NULL;
+
+  s = *pstack;
+  v = s->name;
+  *pstack = (*pstack)->next;
+  free (s);
+
+  return v;
+}
+\f
+/*
+ * Language-dependencies
+ */
+
+/* Common entry points */
+
+/* Get the language of variable VAR. */
+static enum varobj_languages
+variable_language (var)
+     struct varobj *var;
+{
+  enum varobj_languages lang;
+
+  switch (var->root->exp->language_defn->la_language)
+    {
+    default:
+    case language_c:
+      lang = vlang_c;
+      break;
+    case language_cplus:
+      lang = vlang_cplus;
+      break;
+    case language_java:
+      lang = vlang_java;
+      break;
+    }
+
+  return lang;
+}
+
+/* Return the number of children for a given variable.
+   The result of this function is defined by the language
+   implementation. The number of children returned by this function
+   is the number of children that the user will see in the variable
+   display. */
+static int
+number_of_children (var)
+     struct varobj *var;
+{
+  return (*var->root->lang->number_of_children) (var);;
+}
+
+/* What is the expression for the root varobj VAR? Returns a malloc'd string. */
+static char *
+name_of_variable (var)
+     struct varobj *var;
+{
+  return (*var->root->lang->name_of_variable) (var);
+}
+
+/* What is the name of the INDEX'th child of VAR? Returns a malloc'd string. */
+static char *
+name_of_child (var, index)
+     struct varobj *var;
+     int index;
+{
+  return (*var->root->lang->name_of_child) (var, index);
+}
+
+/* What is the value_ptr of the root variable VAR? */
+static value_ptr
+value_of_root (var)
+     struct varobj *var;
+{
+  return (*var->root->lang->value_of_root) (var);
+}
+
+/* What is the value_ptr for the INDEX'th child of PARENT? */
+static value_ptr
+value_of_child (parent, index)
+     struct varobj *parent;
+     int index;
+{
+  value_ptr value;
+
+  value = (*parent->root->lang->value_of_child) (parent, index);
+
+  /* If we're being lazy, fetch the real value of the variable. */
+  if (value != NULL && VALUE_LAZY (value))
+    gdb_value_fetch_lazy (value);
+
+  return value;
+}
+
+/* What is the type of VAR? */
+static struct type *
+type_of_child (var)
+     struct varobj *var;
+{
+
+  /* If the child had no evaluation errors, var->value
+     will be non-NULL and contain a valid type. */
+  if (var->value != NULL)
+    return VALUE_TYPE (var->value);
+
+  /* Otherwise, we must compute the type. */
+  return (*var->root->lang->type_of_child) (var->parent, var->index);
+}
+
+/* Is this variable editable? Use the variable's type to make
+   this determination. */
+static int
+variable_editable (var)
+     struct varobj *var;
+{
+  return (*var->root->lang->variable_editable) (var);
+}
+
+/* GDB already has a command called "value_of_variable". Sigh. */
+static char *
+my_value_of_variable (var)
+     struct varobj *var;
+{
+  return (*var->root->lang->value_of_variable) (var);
+}
+
+/* Is VAR something that can change? Depending on language,
+   some variable's values never change. For example,
+   struct and unions never change values. */
+static int
+type_changeable (var)
+     struct varobj *var;
+{
+  int r;
+  struct type *type;
+
+  if (CPLUS_FAKE_CHILD (var))
+    return 0;
+
+  type = get_type (var);
+
+  switch (TYPE_CODE (type))
+    {
+      case TYPE_CODE_STRUCT:
+      case TYPE_CODE_UNION:
+       r = 0;
+       break;
+
+      default:
+       r = 1;
+    }
+
+  return r;
+}
+
+/* C */
+static int
+c_number_of_children (var)
+     struct varobj *var;
+{
+  struct type *type;
+  struct type *target;
+  int children;
+
+  type = get_type (var);
+  target = get_target_type (type);
+  children = 0;
+
+  switch (TYPE_CODE (type))
+    {
+    case TYPE_CODE_ARRAY:
+      if (TYPE_LENGTH (type) > 0 && TYPE_LENGTH (target) > 0
+       && TYPE_ARRAY_UPPER_BOUND_TYPE (type) != BOUND_CANNOT_BE_DETERMINED)
+       children = TYPE_LENGTH (type) / TYPE_LENGTH (target);
+      else
+       children = -1;
+      break;
+
+    case TYPE_CODE_STRUCT:
+    case TYPE_CODE_UNION:
+      children = TYPE_NFIELDS (type);
+      break;
+
+    case TYPE_CODE_PTR:
+      /* This is where things get compilcated. All pointers have one child.
+         Except, of course, for struct and union ptr, which we automagically
+         dereference for the user and function ptrs, which have no children. */
+      switch (TYPE_CODE (target))
+       {
+       case TYPE_CODE_STRUCT:
+       case TYPE_CODE_UNION:
+         children = TYPE_NFIELDS (target);
+         break;
+
+       case TYPE_CODE_FUNC:
+         children = 0;
+         break;
+
+       default:
+         /* Don't dereference char* or void*. */
+         if (TYPE_NAME (target) != NULL
+             && (STREQ (TYPE_NAME (target), "char")
+                 || STREQ (TYPE_NAME (target), "void")))
+           children = 0;
+         else
+           children = 1;
+       }
+      break;
+
+    default:
+      /* Other types have no children */
+      break;
+    }
+
+  return children;
+}
+
+static char *
+c_name_of_variable (parent)
+     struct varobj *parent;
+{
+  return savestring (parent->name, strlen (parent->name));
+}
+
+static char *
+c_name_of_child (parent, index)
+     struct varobj *parent;
+     int index;
+{
+  struct type *type;
+  struct type *target;
+  char *name;
+  char *string;
+
+  type = get_type (parent);
+  target = get_target_type (type);
+
+  switch (TYPE_CODE (type))
+    {
+    case TYPE_CODE_ARRAY:
+      {
+       /* We never get here unless parent->num_children is greater than 0... */
+       int len = 1;
+       while ((int) pow ((double) 10, (double) len) < index)
+         len++;
+       name = (char *) xmalloc (1 + len * sizeof (char));
+       sprintf (name, "%d", index);
+      }
+      break;
+
+    case TYPE_CODE_STRUCT:
+    case TYPE_CODE_UNION:
+      string = TYPE_FIELD_NAME (type, index);
+      name = savestring (string, strlen (string));
+      break;
+
+    case TYPE_CODE_PTR:
+      switch (TYPE_CODE (target))
+       {
+       case TYPE_CODE_STRUCT:
+       case TYPE_CODE_UNION:
+         string = TYPE_FIELD_NAME (target, index);
+         name = savestring (string, strlen (string));
+         break;
+
+       default:
+         name = (char *) xmalloc ((strlen (parent->name) + 2) * sizeof (char));
+         sprintf (name, "*%s", parent->name);
+         break;
+       }
+      break;
+
+    default:
+      /* This should not happen */
+      name = xstrdup ("???");
+    }
+
+  return name;
+}
+
+static value_ptr
+c_value_of_root (var)
+     struct varobj *var;
+{
+  value_ptr new_val;
+  struct frame_info *fi;
+  int within_scope;
+
+  /* Determine whether the variable is still around. */
+  if (var->root->valid_block == NULL)
+    within_scope = 1;
+  else
+    {
+      reinit_frame_cache ();
+      fi = find_frame_addr_in_frame_chain (var->root->frame);
+      within_scope = fi != NULL;
+      /* FIXME: select_frame could fail */
+      if (within_scope)
+       select_frame (fi, -1);
+    }
+
+  if (within_scope)
+    {
+      /* We need to catch errors here, because if evaluate expression fails
+         we just want to make val->error = 1 and go on */
+      if (gdb_evaluate_expression (var->root->exp, &new_val))
+       {
+         if (VALUE_LAZY (new_val))
+           {
+             /* We need to catch errors because if value_fetch_lazy fails we
+                still want to continue (after making val->error = 1) */
+             /* FIXME: Shouldn't be using VALUE_CONTENTS?  The comment on
+                value_fetch_lazy() says it is only called from the macro... */
+             if (!gdb_value_fetch_lazy (new_val))
+               var->error = 1;
+             else
+               var->error = 0;
+           }
+       }
+      else
+       var->error = 1;
+
+      release_value (new_val);
+      return new_val;
+    }
+
+  return NULL;
+}
+
+static value_ptr
+c_value_of_child (parent, index)
+     struct varobj *parent;
+     int index;
+{
+  value_ptr value, temp;
+  struct type *type, *target;
+  char *name;
+
+  type = get_type (parent);
+  target = get_target_type (type);
+  name = name_of_child (parent, index);
+  temp = parent->value;
+  value = NULL;
+
+  if (temp != NULL)
+    {
+      switch (TYPE_CODE (type))
+       {
+       case TYPE_CODE_ARRAY:
+         value = value_slice (temp, index, 1);
+         temp = value_coerce_array (value);
+         gdb_value_ind (temp, &value);
+         break;
+
+       case TYPE_CODE_STRUCT:
+       case TYPE_CODE_UNION:
+         value = value_struct_elt (&temp, NULL, name, NULL, "vstructure");
+         break;
+
+       case TYPE_CODE_PTR:
+         switch (TYPE_CODE (target))
+           {
+           case TYPE_CODE_STRUCT:
+           case TYPE_CODE_UNION:
+             value = value_struct_elt (&temp, NULL, name, NULL, "vstructure");
+             break;
+
+           default:
+             gdb_value_ind (temp, &value);
+             break;
+           }
+         break;
+
+       default:
+         break;
+       }
+    }
+
+  if (value != NULL)
+    release_value (value);
+
+  return value;
+}
+
+static struct type *
+c_type_of_child (parent, index)
+     struct varobj *parent;
+     int index;
+{
+  struct type *type;
+  char *name = name_of_child (parent, index);
+
+  switch (TYPE_CODE (parent->type))
+    {
+    case TYPE_CODE_ARRAY:
+      type = TYPE_TARGET_TYPE (parent->type);
+      break;
+
+    case TYPE_CODE_STRUCT:
+    case TYPE_CODE_UNION:
+      type = lookup_struct_elt_type (parent->type, name, 0);
+      break;
+
+    case TYPE_CODE_PTR:
+      switch (TYPE_CODE (TYPE_TARGET_TYPE (parent->type)))
+       {
+       case TYPE_CODE_STRUCT:
+       case TYPE_CODE_UNION:
+         type = lookup_struct_elt_type (parent->type, name, 0);
+         break;
+
+       default:
+         type = TYPE_TARGET_TYPE (parent->type);
+         break;
+       }
+      break;
+
+    default:
+      /* This should not happen as only the above types have children */
+      warning ("Child of parent whose type does not allow children");
+      /* FIXME: Can we still go on? */
+      type = NULL;
+      break;
+    }
+
+  return type;
+}
+
+static int
+c_variable_editable (var)
+     struct varobj *var;
+{
+  switch (TYPE_CODE (get_type (var)))
+    {
+    case TYPE_CODE_STRUCT:
+    case TYPE_CODE_UNION:
+    case TYPE_CODE_ARRAY:
+    case TYPE_CODE_FUNC:
+    case TYPE_CODE_MEMBER:
+    case TYPE_CODE_METHOD:
+      return 0;
+      break;
+
+    default:
+      return 1;
+      break;
+    }
+}
+
+static char *
+c_value_of_variable (var)
+     struct varobj *var;
+{
+  struct type *type;
+  value_ptr val;
+
+  if (var->value != NULL)
+    val = var->value;
+  else
+    {
+      /* This can happen if we attempt to get the value of a struct
+         member when the parent is an invalid pointer. */
+      return xstrdup ("???");
+    }
+
+  /* BOGUS: if val_print sees a struct/class, it will print out its
+     children instead of "{...}" */
+  type = get_type (var);
+  switch (TYPE_CODE (type))
+    {
+    case TYPE_CODE_STRUCT:
+    case TYPE_CODE_UNION:
+      return xstrdup ("{...}");
+      /* break; */
+
+    case TYPE_CODE_ARRAY:
+      {
+       char number[18];
+       sprintf (number, "[%d]", var->num_children);
+       return xstrdup (number);
+      }
+      /* break; */
+
+    default:
+      {
+       long dummy;
+       struct ui_file *stb = mem_fileopen ();
+       struct cleanup *old_chain = make_cleanup_ui_file_delete (stb);
+       char *thevalue;
+
+       if (VALUE_LAZY (val))
+         gdb_value_fetch_lazy (val);
+       val_print (VALUE_TYPE (val), VALUE_CONTENTS_RAW (val), 0,
+                  VALUE_ADDRESS (val),
+                  stb, format_code[(int) var->format], 1, 0, 0);
+       thevalue = ui_file_xstrdup (stb, &dummy);
+       do_cleanups (old_chain);
+       return thevalue;
+      }
+      /* break; */
+    }
+}
+\f
+
+/* C++ */
+
+static int
+cplus_number_of_children (var)
+     struct varobj *var;
+{
+  struct type *type;
+  int children, dont_know;
+
+  dont_know = 1;
+  children = 0;
+
+  if (!CPLUS_FAKE_CHILD (var))
+    {
+      type = get_type_deref (var);
+
+      if (((TYPE_CODE (type)) == TYPE_CODE_STRUCT) ||
+          ((TYPE_CODE (type)) == TYPE_CODE_UNION))
+       {
+         int kids[3];
+
+         cplus_class_num_children (type, kids);
+         if (kids[v_public] != 0)
+           children++;
+         if (kids[v_private] != 0)
+           children++;
+         if (kids[v_protected] != 0)
+           children++;
+
+         /* Add any baseclasses */
+         children += TYPE_N_BASECLASSES (type);
+         dont_know = 0;
+
+         /* FIXME: save children in var */
+       }
+    }
+  else
+    {
+      int kids[3];
+
+      type = get_type_deref (var->parent);
+
+      cplus_class_num_children (type, kids);
+      if (STREQ (var->name, "public"))
+       children = kids[v_public];
+      else if (STREQ (var->name, "private"))
+       children = kids[v_private];
+      else
+       children = kids[v_protected];
+      dont_know = 0;
+    }
+
+  if (dont_know)
+    children = c_number_of_children (var);
+
+  return children;
+}
+
+/* Compute # of public, private, and protected variables in this class.
+   That means we need to descend into all baseclasses and find out
+   how many are there, too. */
+static void
+cplus_class_num_children (type, children)
+     struct type *type;
+     int children[3];
+{
+  int i;
+
+  children[v_public] = 0;
+  children[v_private] = 0;
+  children[v_protected] = 0;
+
+  for (i = TYPE_N_BASECLASSES (type); i < TYPE_NFIELDS (type); i++)
+    {
+      /* If we have a virtual table pointer, omit it. */
+      if (TYPE_VPTR_BASETYPE (type) == type
+         && TYPE_VPTR_FIELDNO (type) == i)
+       continue;
+
+      if (TYPE_FIELD_PROTECTED (type, i))
+       children[v_protected]++;
+      else if (TYPE_FIELD_PRIVATE (type, i))
+       children[v_private]++;
+      else
+       children[v_public]++;
+    }
+}
+
+static char *
+cplus_name_of_variable (parent)
+     struct varobj *parent;
+{
+  return c_name_of_variable (parent);
+}
+
+static char *
+cplus_name_of_child (parent, index)
+     struct varobj *parent;
+     int index;
+{
+  char *name;
+  struct type *type;
+  int children[3];
+
+  if (CPLUS_FAKE_CHILD (parent))
+    {
+      /* Looking for children of public, private, or protected. */
+      type = get_type_deref (parent->parent);
+    }
+  else
+    type = get_type_deref (parent);
+
+  name = NULL;
+  switch (TYPE_CODE (type))
+    {
+    case TYPE_CODE_STRUCT:
+    case TYPE_CODE_UNION:
+      cplus_class_num_children (type, children);
+
+      if (CPLUS_FAKE_CHILD (parent))
+       {
+         /* FIXME: This assumes that type orders
+            inherited, public, private, protected */
+         int i = index + TYPE_N_BASECLASSES (type);
+         if (STREQ (parent->name, "private") || STREQ (parent->name, "protected"))
+           i += children[v_public];
+         if (STREQ (parent->name, "protected"))
+           i += children[v_private];
+
+         name = TYPE_FIELD_NAME (type, i);
+       }
+      else if (index < TYPE_N_BASECLASSES (type))
+       name = TYPE_FIELD_NAME (type, index);
+      else
+       {
+         /* Everything beyond the baseclasses can
+            only be "public", "private", or "protected" */
+         index -= TYPE_N_BASECLASSES (type);
+         switch (index)
+           {
+           case 0:
+             if (children[v_public] != 0)
+               {
+                 name = "public";
+                 break;
+               }
+           case 1:
+             if (children[v_private] != 0)
+               {
+                 name = "private";
+                 break;
+               }
+           case 2:
+             if (children[v_protected] != 0)
+               {
+                 name = "protected";
+                 break;
+               }
+           default:
+             /* error! */
+             break;
+           }
+       }
+      break;
+
+    default:
+      break;
+    }
+
+  if (name == NULL)
+    return c_name_of_child (parent, index);
+  else
+    {
+      if (name != NULL)
+       name = savestring (name, strlen (name));
+    }
+
+  return name;
+}
+
+static value_ptr
+cplus_value_of_root (var)
+     struct varobj *var;
+{
+  return c_value_of_root (var);
+}
+
+static value_ptr
+cplus_value_of_child (parent, index)
+     struct varobj *parent;
+     int index;
+{
+  struct type *type;
+  value_ptr value;
+  char *name;
+
+  if (CPLUS_FAKE_CHILD (parent))
+    type = get_type_deref (parent->parent);
+  else
+    type = get_type_deref (parent);
+
+  value = NULL;
+  name = name_of_child (parent, index);
+
+  if (((TYPE_CODE (type)) == TYPE_CODE_STRUCT) ||
+      ((TYPE_CODE (type)) == TYPE_CODE_UNION))
+    {
+      if (CPLUS_FAKE_CHILD (parent))
+       {
+         value_ptr temp = parent->parent->value;
+         value = value_struct_elt (&temp, NULL, name,
+                                   NULL, "cplus_structure");
+         release_value (value);
+       }
+      else if (index >= TYPE_N_BASECLASSES (type))
+       {
+         /* public, private, or protected */
+         return NULL;
+       }
+      else
+       {
+         /* Baseclass */
+         if (parent->value != NULL)
+           {
+             value_ptr temp;
+
+             if (TYPE_CODE (VALUE_TYPE (parent->value)) == TYPE_CODE_PTR
+                 || TYPE_CODE (VALUE_TYPE (parent->value)) == TYPE_CODE_REF)
+               gdb_value_ind (parent->value, &temp);
+             else
+               temp = parent->value;
+
+             value = value_cast (TYPE_FIELD_TYPE (type, index), temp);
+             release_value (value);
+           }
+       }
+    }
+
+  if (value == NULL)
+    return c_value_of_child (parent, index);
+
+  return value;
+}
+
+static struct type *
+cplus_type_of_child (parent, index)
+     struct varobj *parent;
+     int index;
+{
+  struct type *type, *t;
+
+  t = get_type_deref (parent);
+  type = NULL;
+  switch (TYPE_CODE (t))
+    {
+    case TYPE_CODE_STRUCT:
+    case TYPE_CODE_UNION:
+      if (index >= TYPE_N_BASECLASSES (t))
+       {
+         /* special */
+         return NULL;
+       }
+      else
+       {
+         /* Baseclass */
+         type = TYPE_FIELD_TYPE (t, index);
+       }
+      break;
+
+    default:
+      break;
+    }
+
+  if (type == NULL)
+    return c_type_of_child (parent, index);
+
+  return type;
+}
+
+static int
+cplus_variable_editable (var)
+     struct varobj *var;
+{
+  if (CPLUS_FAKE_CHILD (var))
+    return 0;
+
+  return c_variable_editable (var);
+}
+
+static char *
+cplus_value_of_variable (var)
+     struct varobj *var;
+{
+
+  /* If we have one of our special types, don't print out
+     any value. */
+  if (CPLUS_FAKE_CHILD (var))
+    return xstrdup ("");
+
+  return c_value_of_variable (var);
+}
+\f
+/* Java */
+
+static int
+java_number_of_children (var)
+     struct varobj *var;
+{
+  return cplus_number_of_children (var);
+}
+
+static char *
+java_name_of_variable (parent)
+     struct varobj *parent;
+{
+  char *p, *name;
+
+  name = cplus_name_of_variable (parent);
+  /* If  the name has "-" in it, it is because we
+     needed to escape periods in the name... */
+  p = name;
+
+  while (*p != '\000')
+    {
+      if (*p == '-')
+       *p = '.';
+      p++;
+    }
+
+  return name;
+}
+
+static char *
+java_name_of_child (parent, index)
+     struct varobj *parent;
+     int index;
+{
+  char *name, *p;
+
+  name = cplus_name_of_child (parent, index);
+  /* Escape any periods in the name... */
+  p = name;
+
+  while (*p != '\000')
+    {
+      if (*p == '.')
+       *p = '-';
+      p++;
+    }
+
+  return name;
+}
+
+static value_ptr
+java_value_of_root (var)
+     struct varobj *var;
+{
+  return cplus_value_of_root (var);
+}
+
+static value_ptr
+java_value_of_child (parent, index)
+     struct varobj *parent;
+     int index;
+{
+  return cplus_value_of_child (parent, index);
+}
+
+static struct type *
+java_type_of_child (parent, index)
+     struct varobj *parent;
+     int index;
+{
+  return cplus_type_of_child (parent, index);
+}
+
+static int
+java_variable_editable (var)
+     struct varobj *var;
+{
+  return cplus_variable_editable (var);
+}
+
+static char *
+java_value_of_variable (var)
+     struct varobj *var;
+{
+  return cplus_value_of_variable (var);
+}
+\f
+extern void _initialize_varobj (void);
+void
+_initialize_varobj (void)
+{
+  int sizeof_table = sizeof (struct vlist *) * VAROBJ_TABLE_SIZE;
+
+  varobj_table = xmalloc (sizeof_table);
+  memset (varobj_table, 0, sizeof_table);
+
+  add_show_from_set (
+               add_set_cmd ("debugvarobj", class_maintenance, var_zinteger,
+                            (char *) &varobjdebug,
+                            "Set varobj debugging.\n\
+When non-zero, varobj debugging is enabled.", &setlist),
+                     &showlist);
+}
diff --git a/gdb/varobj.h b/gdb/varobj.h
new file mode 100644 (file)
index 0000000..28c5fac
--- /dev/null
@@ -0,0 +1,92 @@
+/* GDB variable objects API.
+   Copyright 1999 Free Software Foundation, Inc.
+
+   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 VAROBJ_H
+#define VAROBJ_H 1
+
+#include "symtab.h"
+#include "gdbtypes.h"
+
+/* Enumeration for the format types */
+enum varobj_display_formats
+  {
+    FORMAT_NATURAL,            /* What gdb actually calls 'natural' */
+    FORMAT_BINARY,             /* Binary display                    */
+    FORMAT_DECIMAL,            /* Decimal display                   */
+    FORMAT_HEXADECIMAL,                /* Hex display                       */
+    FORMAT_OCTAL               /* Octal display                     */
+  };
+
+/* String representations of gdb's format codes (defined in varobj.c) */
+extern char *varobj_format_string[];
+
+/* Languages supported by this variable objects system. */
+enum varobj_languages
+  {
+    vlang_unknown = 0, vlang_c, vlang_cplus, vlang_java, vlang_end
+  };
+
+/* String representations of gdb's known languages (defined in varobj.c) */
+extern char *varobj_language_string[];
+
+/* Struct thar describes a variable object instance */
+struct varobj;
+
+/* API functions */
+
+extern struct varobj *varobj_create (char *objname,
+                                    char *expression, CORE_ADDR frame);
+
+extern char *varobj_gen_name (void);
+
+extern struct varobj *varobj_get_handle (char *name);
+
+extern char *varobj_get_objname (struct varobj *var);
+
+extern char *varobj_get_expression (struct varobj *var);
+
+extern int varobj_delete (struct varobj *var, char ***dellist,
+                         int only_children);
+
+extern enum varobj_display_formats varobj_set_display_format (
+                                                        struct varobj *var,
+                                       enum varobj_display_formats format);
+
+extern enum varobj_display_formats varobj_get_display_format (
+                                                       struct varobj *var);
+
+extern int varobj_get_num_children (struct varobj *var);
+
+extern int varobj_list_children (struct varobj *var,
+                                struct varobj ***childlist);
+
+extern char *varobj_get_type (struct varobj *var);
+
+extern enum varobj_languages varobj_get_language (struct varobj *var);
+
+extern int varobj_get_attributes (struct varobj *var);
+
+extern char *varobj_get_value (struct varobj *var);
+
+extern int varobj_set_value (struct varobj *var, char *expression);
+
+extern int varobj_list (struct varobj ***rootlist);
+
+extern int varobj_update (struct varobj *var, struct varobj ***changelist);
+
+#endif /* VAROBJ_H */
diff --git a/gdb/wrapper.c b/gdb/wrapper.c
new file mode 100644 (file)
index 0000000..be7d4e2
--- /dev/null
@@ -0,0 +1,165 @@
+/* Longjump free calls to gdb internal routines.
+   Copyright 1999 Free Software Foundation, Inc.
+
+   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 "value.h"
+#include "frame.h"
+#include "wrapper.h"
+
+/* Use this struct used to pass arguments to wrapper routines. We assume
+   (arbitrarily) that no gdb function takes more than ten arguments. */
+struct gdb_wrapper_arguments
+  {
+
+    /* Pointer to some result from the gdb function call, if any */
+    char *result;
+
+    /* The list of arguments. */
+    char *args[10];
+  };
+
+int gdb_evaluate_expression PARAMS ((struct expression *, value_ptr *));
+int wrap_evaluate_expression PARAMS ((char *));
+
+int gdb_value_fetch_lazy PARAMS ((value_ptr));
+int wrap_value_fetch_lazy PARAMS ((char *));
+
+int gdb_value_equal PARAMS ((value_ptr, value_ptr, int *));
+int wrap_value_equal PARAMS ((char *));
+
+int gdb_value_ind PARAMS ((value_ptr val, value_ptr * rval));
+int wrap_value_ind PARAMS ((char *opaque_arg));
+
+int
+gdb_evaluate_expression (exp, value)
+     struct expression *exp;
+     value_ptr *value;
+{
+  struct gdb_wrapper_arguments args;
+  args.args[0] = (char *) exp;
+
+  if (!catch_errors ((catch_errors_ftype *) wrap_evaluate_expression, &args,
+                    "", RETURN_MASK_ERROR))
+    {
+      /* An error occurred */
+      return 0;
+    }
+
+  *value = (value_ptr) args.result;
+  return 1;
+}
+
+int
+wrap_evaluate_expression (a)
+     char *a;
+{
+  struct gdb_wrapper_arguments *args = (struct gdb_wrapper_arguments *) a;
+
+  (args)->result =
+    (char *) evaluate_expression ((struct expression *) (args)->args[0]);
+  return 1;
+}
+
+int
+gdb_value_fetch_lazy (value)
+     value_ptr value;
+{
+  struct gdb_wrapper_arguments args;
+
+  args.args[0] = (char *) value;
+  return catch_errors ((catch_errors_ftype *) wrap_value_fetch_lazy, &args,
+                      "", RETURN_MASK_ERROR);
+}
+
+int
+wrap_value_fetch_lazy (a)
+     char *a;
+{
+  struct gdb_wrapper_arguments *args = (struct gdb_wrapper_arguments *) a;
+
+  value_fetch_lazy ((value_ptr) (args)->args[0]);
+  return 1;
+}
+
+int
+gdb_value_equal (val1, val2, result)
+     value_ptr val1;
+     value_ptr val2;
+     int *result;
+{
+  struct gdb_wrapper_arguments args;
+
+  args.args[0] = (char *) val1;
+  args.args[1] = (char *) val2;
+
+  if (!catch_errors ((catch_errors_ftype *) wrap_value_equal, &args,
+                    "", RETURN_MASK_ERROR))
+    {
+      /* An error occurred */
+      return 0;
+    }
+
+  *result = (int) args.result;
+  return 1;
+}
+
+int
+wrap_value_equal (a)
+     char *a;
+{
+  struct gdb_wrapper_arguments *args = (struct gdb_wrapper_arguments *) a;
+  value_ptr val1, val2;
+
+  val1 = (value_ptr) (args)->args[0];
+  val2 = (value_ptr) (args)->args[1];
+
+  (args)->result = (char *) value_equal (val1, val2);
+  return 1;
+}
+
+int
+gdb_value_ind (val, rval)
+     value_ptr val;
+     value_ptr *rval;
+{
+  struct gdb_wrapper_arguments args;
+
+  args.args[0] = (char *) val;
+
+  if (!catch_errors ((catch_errors_ftype *) wrap_value_ind, &args,
+                    "", RETURN_MASK_ERROR))
+    {
+      /* An error occurred */
+      return 0;
+    }
+
+  *rval = (value_ptr) args.result;
+  return 1;
+}
+
+int
+wrap_value_ind (opaque_arg)
+     char *opaque_arg;
+{
+  struct gdb_wrapper_arguments *args = (struct gdb_wrapper_arguments *) opaque_arg;
+  value_ptr val;
+
+  val = (value_ptr) (args)->args[0];
+  (args)->result = (char *) value_ind (val);
+  return 1;
+}
diff --git a/gdb/wrapper.h b/gdb/wrapper.h
new file mode 100644 (file)
index 0000000..f4303b2
--- /dev/null
@@ -0,0 +1,37 @@
+/* Longjump free calls to gdb internal routines.
+   Copyright 1999 Free Software Foundation, Inc.
+
+   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 WRAPPER_H
+#define WRAPPER_H 1
+
+/* Use this struct used to pass arguments to wrapper routines. */
+struct gdb_wrapper_arguments;
+
+extern int gdb_evaluate_expression PARAMS ((struct expression *, value_ptr *));
+extern int wrap_evaluate_expression PARAMS ((char *));
+
+extern int gdb_value_fetch_lazy PARAMS ((value_ptr));
+extern int wrap_value_fetch_lazy PARAMS ((char *));
+
+extern int gdb_value_equal PARAMS ((value_ptr, value_ptr, int *));
+extern int wrap_value_equal PARAMS ((char *));
+
+extern int gdb_value_ind PARAMS ((value_ptr val, value_ptr * rval));
+extern int wrap_value_ind PARAMS ((char *opaque_arg));
+
+#endif /* WRAPPER_H */