Expose current 'print' settings to Python

PR python/17291 asks for access to the current print options.  While I
think this need is largely satisfied by the existence of
Value.format_string, it seemed to me that a bit more could be done.

First, while Value.format_string uses the user's settings, it does not
react to temporary settings such as "print/x".  This patch changes
this.

Second, there is no good way to examine the current settings (in
particular the temporary ones in effect for just a single "print").
This patch adds this as well.

Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=17291
This commit is contained in:
Tom Tromey
2022-06-06 09:54:45 -06:00
parent aa63b0a77e
commit c4a3dbaf11
10 changed files with 209 additions and 26 deletions

View File

@ -39,6 +39,10 @@ enum gdbpy_string_repr_result
string_repr_ok
};
/* If non-null, points to options that are in effect while
printing. */
const struct value_print_options *gdbpy_current_print_options;
/* Helper function for find_pretty_printer which iterates over a list,
calls each function and inspects output. This will return a
printer object if one recognizes VALUE. If no printer is found, it
@ -604,6 +608,9 @@ gdbpy_apply_val_pretty_printer (const struct extension_language_defn *extlang,
if (printer == Py_None)
return EXT_LANG_RC_NOP;
scoped_restore set_options = make_scoped_restore (&gdbpy_current_print_options,
options);
/* If we are printing a map, we want some special formatting. */
gdb::unique_xmalloc_ptr<char> hint (gdbpy_get_display_hint (printer.get ()));
@ -632,8 +639,12 @@ gdbpy_apply_val_pretty_printer (const struct extension_language_defn *extlang,
gdbpy_ref<>
apply_varobj_pretty_printer (PyObject *printer_obj,
struct value **replacement,
struct ui_file *stream)
struct ui_file *stream,
const value_print_options *opts)
{
scoped_restore set_options = make_scoped_restore (&gdbpy_current_print_options,
opts);
*replacement = NULL;
gdbpy_ref<> py_str = pretty_print_one_value (printer_obj, replacement);
@ -688,3 +699,88 @@ gdbpy_default_visualizer (PyObject *self, PyObject *args)
return find_pretty_printer (val_obj).release ();
}
/* Helper function to set a boolean in a dictionary. */
static int
set_boolean (PyObject *dict, const char *name, bool val)
{
gdbpy_ref<> val_obj (PyBool_FromLong (val));
if (val_obj == nullptr)
return -1;
return PyDict_SetItemString (dict, name, val_obj.get ());
}
/* Helper function to set an integer in a dictionary. */
static int
set_unsigned (PyObject *dict, const char *name, unsigned int val)
{
gdbpy_ref<> val_obj = gdb_py_object_from_ulongest (val);
if (val_obj == nullptr)
return -1;
return PyDict_SetItemString (dict, name, val_obj.get ());
}
/* Implement gdb.print_options. */
PyObject *
gdbpy_print_options (PyObject *unused1, PyObject *unused2)
{
gdbpy_ref<> result (PyDict_New ());
if (result == nullptr)
return nullptr;
value_print_options opts;
gdbpy_get_print_options (&opts);
if (set_boolean (result.get (), "raw",
opts.raw) < 0
|| set_boolean (result.get (), "pretty_arrays",
opts.prettyformat_arrays) < 0
|| set_boolean (result.get (), "pretty_structs",
opts.prettyformat_structs) < 0
|| set_boolean (result.get (), "array_indexes",
opts.print_array_indexes) < 0
|| set_boolean (result.get (), "symbols",
opts.symbol_print) < 0
|| set_boolean (result.get (), "unions",
opts.unionprint) < 0
|| set_boolean (result.get (), "address",
opts.addressprint) < 0
|| set_boolean (result.get (), "deref_refs",
opts.deref_ref) < 0
|| set_boolean (result.get (), "actual_objects",
opts.objectprint) < 0
|| set_boolean (result.get (), "static_members",
opts.static_field_print) < 0
|| set_boolean (result.get (), "deref_refs",
opts.deref_ref) < 0
|| set_unsigned (result.get (), "max_elements",
opts.print_max) < 0
|| set_unsigned (result.get (), "max_depth",
opts.max_depth) < 0
|| set_unsigned (result.get (), "repeat_threshold",
opts.repeat_count_threshold) < 0)
return nullptr;
if (opts.format != 0)
{
char str[2] = { (char) opts.format, 0 };
gdbpy_ref<> fmtstr = host_string_to_python_string (str);
if (fmtstr == nullptr)
return nullptr;
if (PyDict_SetItemString (result.get (), "format", fmtstr.get ()) < 0)
return nullptr;
}
return result.release ();
}
/* Helper function that either finds the prevailing print options, or
calls get_user_print_options. */
void
gdbpy_get_print_options (value_print_options *opts)
{
if (gdbpy_current_print_options != nullptr)
*opts = *gdbpy_current_print_options;
else
get_user_print_options (opts);
}

View File

@ -673,7 +673,7 @@ valpy_format_string (PyObject *self, PyObject *args, PyObject *kw)
}
struct value_print_options opts;
get_user_print_options (&opts);
gdbpy_get_print_options (&opts);
opts.deref_ref = 0;
/* We need objects for booleans as the "p" flag for bools is new in
@ -1163,7 +1163,7 @@ valpy_str (PyObject *self)
{
struct value_print_options opts;
get_user_print_options (&opts);
gdbpy_get_print_options (&opts);
opts.deref_ref = 0;
string_file stb;

View File

@ -17,13 +17,15 @@
#include "python-internal.h"
#include "varobj.h"
#include "varobj-iter.h"
#include "valprint.h"
/* A dynamic varobj iterator "class" for python pretty-printed
varobjs. This inherits struct varobj_iter. */
struct py_varobj_iter : public varobj_iter
{
py_varobj_iter (struct varobj *var, gdbpy_ref<> &&pyiter);
py_varobj_iter (struct varobj *var, gdbpy_ref<> &&pyiter,
const value_print_options *opts);
~py_varobj_iter () override;
std::unique_ptr<varobj_item> next () override;
@ -41,6 +43,9 @@ private:
/* The python iterator returned by the printer's 'children' method,
or NULL if not available. */
PyObject *m_iter;
/* The print options to use. */
value_print_options m_opts;
};
/* Implementation of the 'dtor' method of pretty-printed varobj
@ -67,6 +72,9 @@ py_varobj_iter::next ()
gdbpy_enter_varobj enter_py (m_var);
scoped_restore set_options = make_scoped_restore (&gdbpy_current_print_options,
&m_opts);
gdbpy_ref<> item (PyIter_Next (m_iter));
if (item == NULL)
@ -124,9 +132,11 @@ py_varobj_iter::next ()
whose children the iterator will be iterating over. PYITER is the
python iterator actually responsible for the iteration. */
py_varobj_iter::py_varobj_iter (struct varobj *var, gdbpy_ref<> &&pyiter)
py_varobj_iter::py_varobj_iter (struct varobj *var, gdbpy_ref<> &&pyiter,
const value_print_options *opts)
: m_var (var),
m_iter (pyiter.release ())
m_iter (pyiter.release ()),
m_opts (*opts)
{
}
@ -134,13 +144,17 @@ py_varobj_iter::py_varobj_iter (struct varobj *var, gdbpy_ref<> &&pyiter)
over VAR's children. */
std::unique_ptr<varobj_iter>
py_varobj_get_iterator (struct varobj *var, PyObject *printer)
py_varobj_get_iterator (struct varobj *var, PyObject *printer,
const value_print_options *opts)
{
gdbpy_enter_varobj enter_py (var);
if (!PyObject_HasAttr (printer, gdbpy_children_cst))
return NULL;
scoped_restore set_options = make_scoped_restore (&gdbpy_current_print_options,
opts);
gdbpy_ref<> children (PyObject_CallMethodObjArgs (printer, gdbpy_children_cst,
NULL));
if (children == NULL)
@ -157,5 +171,6 @@ py_varobj_get_iterator (struct varobj *var, PyObject *printer)
}
return std::unique_ptr<varobj_iter> (new py_varobj_iter (var,
std::move (iter)));
std::move (iter),
opts));
}

View File

@ -746,11 +746,16 @@ int gdbpy_is_value_object (PyObject *obj);
other pretty-printer functions, because they refer to PyObject. */
gdbpy_ref<> apply_varobj_pretty_printer (PyObject *print_obj,
struct value **replacement,
struct ui_file *stream);
struct ui_file *stream,
const value_print_options *opts);
gdbpy_ref<> gdbpy_get_varobj_pretty_printer (struct value *value);
gdb::unique_xmalloc_ptr<char> gdbpy_get_display_hint (PyObject *printer);
PyObject *gdbpy_default_visualizer (PyObject *self, PyObject *args);
PyObject *gdbpy_print_options (PyObject *self, PyObject *args);
void gdbpy_get_print_options (value_print_options *opts);
extern const struct value_print_options *gdbpy_current_print_options;
void bpfinishpy_pre_stop_hook (struct gdbpy_breakpoint_object *bp_obj);
void bpfinishpy_post_stop_hook (struct gdbpy_breakpoint_object *bp_obj);
@ -784,8 +789,10 @@ int gdb_pymodule_addobject (PyObject *module, const char *name,
struct varobj_iter;
struct varobj;
std::unique_ptr<varobj_iter> py_varobj_get_iterator (struct varobj *var,
PyObject *printer);
std::unique_ptr<varobj_iter> py_varobj_get_iterator
(struct varobj *var,
PyObject *printer,
const value_print_options *opts);
/* Deleter for Py_buffer unique_ptr specialization. */

View File

@ -2560,6 +2560,10 @@ the returned string is 'ADDRESS <SYMBOL+OFFSET>' without the quotes." },
"current_language () -> string\n\
Return the name of the currently selected language." },
{ "print_options", gdbpy_print_options, METH_NOARGS,
"print_options () -> dict\n\
Return the current print options." },
{NULL, NULL, 0, NULL}
};