summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/cli-out.c339
-rw-r--r--gdb/cli-out.h27
-rw-r--r--gdb/ui-out.c1007
-rw-r--r--gdb/ui-out.h221
-rw-r--r--gdb/varobj.c2421
-rw-r--r--gdb/varobj.h92
-rw-r--r--gdb/wrapper.c165
-rw-r--r--gdb/wrapper.h37
8 files changed, 4309 insertions, 0 deletions
diff --git a/gdb/cli-out.c b/gdb/cli-out.c
new file mode 100644
index 00000000000..d906510aba3
--- /dev/null
+++ b/gdb/cli-out.c
@@ -0,0 +1,339 @@
+/* Output generating routines for GDB CLI.
+ 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 "ui-out.h"
+#include "cli-out.h"
+
+/* Convenience macro for allocting typesafe memory. */
+
+#ifndef XMALLOC
+#define XMALLOC(TYPE) (TYPE*) xmalloc (sizeof (TYPE))
+#endif
+
+struct ui_out_data
+ {
+ struct ui_file *stream;
+ };
+
+/* These are the CLI output functions */
+
+static void cli_table_begin (struct ui_out *uiout, int nbrofcols, char *tblid);
+static void cli_table_body (struct ui_out *uiout);
+static void cli_table_end (struct ui_out *uiout);
+static void cli_table_header (struct ui_out *uiout, int width,
+ enum ui_align alig, char *colhdr);
+static void cli_list_begin (struct ui_out *uiout, int list_flag, char *lstid);
+static void cli_list_end (struct ui_out *uiout, int list_flag);
+static void cli_field_int (struct ui_out *uiout, int fldno, int width,
+ enum ui_align alig, char *fldname, int value);
+static void cli_field_skip (struct ui_out *uiout, int fldno, int width,
+ enum ui_align alig, char *fldname);
+static void cli_field_string (struct ui_out *uiout, int fldno, int width,
+ enum ui_align alig, char *fldname,
+ const char *string);
+static void cli_field_fmt (struct ui_out *uiout, int fldno,
+ int width, enum ui_align align,
+ char *fldname, char *format, va_list args);
+static void cli_spaces (struct ui_out *uiout, int numspaces);
+static void cli_text (struct ui_out *uiout, char *string);
+static void cli_message (struct ui_out *uiout, int verbosity, char *format,
+ va_list args);
+static void cli_wrap_hint (struct ui_out *uiout, char *identstring);
+static void cli_flush (struct ui_out *uiout);
+
+/* This is the CLI ui-out implementation functions vector */
+
+/* FIXME: This can be initialized dynamically after default is set to
+ handle initial output in main.c */
+
+static struct ui_out_impl cli_ui_out_impl =
+{
+ cli_table_begin,
+ cli_table_body,
+ cli_table_end,
+ cli_table_header,
+ cli_list_begin,
+ cli_list_end,
+ cli_field_int,
+ cli_field_skip,
+ cli_field_string,
+ cli_field_fmt,
+ cli_spaces,
+ cli_text,
+ cli_message,
+ cli_wrap_hint,
+ cli_flush
+};
+
+/* Prototypes for local functions */
+
+extern void _initialize_cli_out PARAMS ((void));
+
+static void field_separator (void);
+
+static void out_field_fmt (struct ui_out *uiout, int fldno, char *fldname,
+ char *format,...);
+
+/* local variables */
+
+/* (none yet) */
+
+/* Mark beginning of a table */
+
+void
+cli_table_begin (uiout, nbrofcols, tblid)
+ struct ui_out *uiout;
+ int nbrofcols;
+ char *tblid;
+{
+}
+
+/* Mark beginning of a table body */
+
+void
+cli_table_body (uiout)
+ struct ui_out *uiout;
+{
+ /* first, close the table header line */
+ cli_text (uiout, "\n");
+}
+
+/* Mark end of a table */
+
+void
+cli_table_end (uiout)
+ struct ui_out *uiout;
+{
+}
+
+/* Specify table header */
+
+void
+cli_table_header (uiout, width, alignment, colhdr)
+ struct ui_out *uiout;
+ int width;
+ int alignment;
+ char *colhdr;
+{
+ cli_field_string (uiout, 0, width, alignment, 0, colhdr);
+}
+
+/* Mark beginning of a list */
+
+void
+cli_list_begin (uiout, list_flag, lstid)
+ struct ui_out *uiout;
+ int list_flag;
+ char *lstid;
+{
+}
+
+/* Mark end of a list */
+
+void
+cli_list_end (uiout, list_flag)
+ struct ui_out *uiout;
+ int list_flag;
+{
+}
+
+/* output an int field */
+
+void
+cli_field_int (uiout, fldno, width, alignment, fldname, value)
+ struct ui_out *uiout;
+ int fldno;
+ int width;
+ int alignment;
+ char *fldname;
+ int value;
+{
+ char buffer[20]; /* FIXME: how many chars long a %d can become? */
+
+ sprintf (buffer, "%d", value);
+ cli_field_string (uiout, fldno, width, alignment, fldname, buffer);
+}
+
+/* used to ommit a field */
+
+void
+cli_field_skip (uiout, fldno, width, alignment, fldname)
+ struct ui_out *uiout;
+ int fldno;
+ int width;
+ int alignment;
+ char *fldname;
+{
+ cli_field_string (uiout, fldno, width, alignment, fldname, "");
+}
+
+/* other specific cli_field_* end up here so alignment and field
+ separators are both handled by cli_field_string */
+
+void
+cli_field_string (struct ui_out *uiout,
+ int fldno,
+ int width,
+ int align,
+ char *fldname,
+ const char *string)
+{
+ int before = 0;
+ int after = 0;
+
+ if ((align != ui_noalign) && string)
+ {
+ before = width - strlen (string);
+ if (before <= 0)
+ before = 0;
+ else
+ {
+ if (align == ui_right)
+ after = 0;
+ else if (align == ui_left)
+ {
+ after = before;
+ before = 0;
+ }
+ else
+ /* ui_center */
+ {
+ after = before / 2;
+ before -= after;
+ }
+ }
+ }
+
+ if (before)
+ ui_out_spaces (uiout, before);
+ if (string)
+ out_field_fmt (uiout, fldno, fldname, "%s", string);
+ if (after)
+ ui_out_spaces (uiout, after);
+
+ if (align != ui_noalign)
+ field_separator ();
+}
+
+/* This is the only field function that does not align */
+
+void
+cli_field_fmt (struct ui_out *uiout, int fldno,
+ int width, enum ui_align align,
+ char *fldname, char *format, va_list args)
+{
+ struct ui_out_data *data = ui_out_data (uiout);
+ vfprintf_filtered (data->stream, format, args);
+
+ if (align != ui_noalign)
+ field_separator ();
+}
+
+void
+cli_spaces (uiout, numspaces)
+ struct ui_out *uiout;
+ int numspaces;
+{
+ struct ui_out_data *data = ui_out_data (uiout);
+ print_spaces_filtered (numspaces, data->stream);
+}
+
+void
+cli_text (uiout, string)
+ struct ui_out *uiout;
+ char *string;
+{
+ struct ui_out_data *data = ui_out_data (uiout);
+ fputs_filtered (string, data->stream);
+}
+
+void
+cli_message (struct ui_out *uiout, int verbosity, char *format, va_list args)
+{
+ struct ui_out_data *data = ui_out_data (uiout);
+ if (ui_out_get_verblvl (uiout) >= verbosity)
+ vfprintf_unfiltered (data->stream, format, args);
+}
+
+void
+cli_wrap_hint (uiout, identstring)
+ struct ui_out *uiout;
+ char *identstring;
+{
+ wrap_here (identstring);
+}
+
+void
+cli_flush (uiout)
+ struct ui_out *uiout;
+{
+ struct ui_out_data *data = ui_out_data (uiout);
+ gdb_flush (data->stream);
+}
+
+/* local functions */
+
+/* Like cli_field_fmt, but takes a variable number of args
+ and makes a va_list and does not insert a separator */
+
+/* VARARGS */
+static void
+out_field_fmt (struct ui_out *uiout, int fldno, char *fldname,
+ char *format,...)
+{
+ struct ui_out_data *data = ui_out_data (uiout);
+ va_list args;
+
+ va_start (args, format);
+ vfprintf_filtered (data->stream, format, args);
+
+ va_end (args);
+}
+
+/* access to ui_out format private members */
+
+static void
+field_separator ()
+{
+ struct ui_out_data *data = ui_out_data (uiout);
+ fputc_filtered (' ', data->stream);
+}
+
+/* initalize private members at startup */
+
+struct ui_out *
+cli_out_new (struct ui_file *stream)
+{
+ int flags = ui_source_list;
+
+ struct ui_out_data *data = XMALLOC (struct ui_out_data);
+ data->stream = stream;
+ return ui_out_new (&cli_ui_out_impl, data, flags);
+}
+
+/* standard gdb initialization hook */
+void
+_initialize_cli_out ()
+{
+ /* nothing needs to be done */
+}
diff --git a/gdb/cli-out.h b/gdb/cli-out.h
new file mode 100644
index 00000000000..f017f807a96
--- /dev/null
+++ b/gdb/cli-out.h
@@ -0,0 +1,27 @@
+/* Output generating routines for GDB CLI.
+ Copyright 1999-2000 Free Software Foundation, Inc.
+ Contributed by Cygnus Solutions.
+
+ 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 CLI_OUT_H
+#define CLI_OUT_H
+
+extern struct ui_out *cli_out_new (struct ui_file *stream);
+
+#endif
diff --git a/gdb/ui-out.c b/gdb/ui-out.c
new file mode 100644
index 00000000000..9e400111443
--- /dev/null
+++ b/gdb/ui-out.c
@@ -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
index 00000000000..d8db5885457
--- /dev/null
+++ b/gdb/ui-out.h
@@ -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
index 00000000000..f0740c69672
--- /dev/null
+++ b/gdb/varobj.c
@@ -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)
+
+
+/* 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;
+}
+
+
+/* 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;
+
+}
+
+
+/*
+ * 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;
+}
+
+/*
+ * 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; */
+ }
+}
+
+
+/* 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);
+}
+
+/* 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);
+}
+
+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
index 00000000000..28c5fac4d16
--- /dev/null
+++ b/gdb/varobj.h
@@ -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
index 00000000000..be7d4e27391
--- /dev/null
+++ b/gdb/wrapper.c
@@ -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
index 00000000000..f4303b2264b
--- /dev/null
+++ b/gdb/wrapper.h
@@ -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 */