1 /* Python interface to ui_file_style::color objects.
3 Copyright (C) 2008-2024 Free Software Foundation, Inc.
5 This file is part of GDB.
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
21 #include "python-internal.h"
23 #include "cli/cli-decode.h"
25 /* Colorspace constants and their values. */
29 } colorspace_constants
[] =
31 { "COLORSPACE_MONOCHROME", color_space::MONOCHROME
},
32 { "COLORSPACE_ANSI_8COLOR", color_space::ANSI_8COLOR
},
33 { "COLORSPACE_AIXTERM_16COLOR", color_space::AIXTERM_16COLOR
},
34 { "COLORSPACE_XTERM_256COLOR", color_space::XTERM_256COLOR
},
35 { "COLORSPACE_RGB_24BIT", color_space::RGB_24BIT
},
43 /* Underlying value. */
44 ui_file_style::color color
;
47 extern PyTypeObject colorpy_object_type
;
51 create_color_object (const ui_file_style::color
&color
)
53 gdbpy_ref
<colorpy_object
> color_obj (PyObject_New (colorpy_object
,
54 &colorpy_object_type
));
56 if (color_obj
== nullptr)
59 color_obj
->color
= color
;
60 return gdbpy_ref
<> ((PyObject
*) color_obj
.release ());
65 gdbpy_is_color (PyObject
*obj
)
67 return PyObject_IsInstance (obj
, (PyObject
*) &colorpy_object_type
);
71 const ui_file_style::color
&
72 gdbpy_get_color (PyObject
*obj
)
74 gdb_assert (gdbpy_is_color (obj
));
75 colorpy_object
*self
= (colorpy_object
*) obj
;
79 /* Get an attribute. */
81 get_attr (PyObject
*obj
, PyObject
*attr_name
)
83 if (! PyUnicode_Check (attr_name
))
84 return PyObject_GenericGetAttr (obj
, attr_name
);
86 colorpy_object
*self
= (colorpy_object
*) obj
;
87 const ui_file_style::color
&color
= self
->color
;
89 if (! PyUnicode_CompareWithASCIIString (attr_name
, "colorspace"))
91 int value
= static_cast<int> (color
.colorspace ());
92 return gdb_py_object_from_longest (value
).release ();
95 if (! PyUnicode_CompareWithASCIIString (attr_name
, "is_none"))
96 return PyBool_FromLong (color
.is_none ());
98 if (! PyUnicode_CompareWithASCIIString (attr_name
, "is_indexed"))
99 return PyBool_FromLong (color
.is_indexed ());
101 if (! PyUnicode_CompareWithASCIIString (attr_name
, "is_direct"))
102 return PyBool_FromLong (color
.is_direct ());
104 if (color
.is_indexed ()
105 && ! PyUnicode_CompareWithASCIIString (attr_name
, "index"))
106 return gdb_py_object_from_longest (color
.get_value ()).release ();
108 if (color
.is_direct ()
109 && ! PyUnicode_CompareWithASCIIString (attr_name
, "components"))
114 gdbpy_ref
<> rgb_objects
[3];
115 for (int i
= 0; i
< 3; ++i
)
117 rgb_objects
[i
] = gdb_py_object_from_ulongest (rgb
[i
]);
118 if (rgb_objects
[i
] == nullptr)
122 PyObject
*comp
= PyTuple_New (3);
126 for (int i
= 0; i
< 3; ++i
)
127 PyTuple_SET_ITEM (comp
, i
, rgb_objects
[i
].release ());
132 return PyObject_GenericGetAttr (obj
, attr_name
);
135 /* Implementation of Color.escape_sequence (self, is_fg) -> str. */
138 colorpy_escape_sequence (PyObject
*self
, PyObject
*is_fg_obj
)
140 if (!gdbpy_is_color (self
))
142 PyErr_SetString (PyExc_RuntimeError
,
143 _("Object is not gdb.Color."));
147 if (! PyBool_Check (is_fg_obj
))
149 PyErr_SetString (PyExc_RuntimeError
,
150 _("A boolean argument is required."));
154 bool is_fg
= is_fg_obj
== Py_True
;
155 std::string s
= gdbpy_get_color (self
).to_ansi (is_fg
);
157 return host_string_to_python_string (s
.c_str ()).release ();
160 /* Object initializer; fills color with value.
162 Use: __init__(VALUE = None, COLORSPACE = None)
164 VALUE is a string, integer, RGB-tuple or None.
166 COLORSPACE is the color space index.
168 Returns -1 on error, with a python exception set. */
171 colorpy_init (PyObject
*self
, PyObject
*args
, PyObject
*kwds
)
173 colorpy_object
*obj
= (colorpy_object
*) self
;
174 PyObject
*value_obj
= nullptr;
175 PyObject
*colorspace_obj
= nullptr;
176 color_space colorspace
= color_space::MONOCHROME
;
178 if (! PyArg_ParseTuple (args
, "|OO", &value_obj
, &colorspace_obj
))
185 if (PyLong_Check (colorspace_obj
))
187 long colorspace_id
= -1;
188 if (! gdb_py_int_as_long (colorspace_obj
, &colorspace_id
))
190 if (!color_space_safe_cast (&colorspace
, colorspace_id
))
191 error (_("colorspace %ld is out of range."), colorspace_id
);
193 else if (colorspace_obj
== Py_None
)
194 colorspace_obj
= nullptr;
196 error (_("colorspace must be None or integer"));
199 if (value_obj
== nullptr || value_obj
== Py_None
)
200 obj
->color
= ui_file_style::color (colorspace
, -1);
201 else if (PyLong_Check (value_obj
))
204 if (! gdb_py_int_as_long (value_obj
, &value
))
206 if (value
< 0 || value
> INT_MAX
)
207 error (_("value %ld is out of range."), value
);
209 obj
->color
= ui_file_style::color (colorspace
, value
);
211 obj
->color
= ui_file_style::color (value
);
213 else if (PyTuple_Check (value_obj
))
215 if (colorspace_obj
== nullptr || colorspace
!= color_space::RGB_24BIT
)
216 error (_("colorspace must be gdb.COLORSPACE_RGB_24BIT with "
217 "value of tuple type."));
218 Py_ssize_t tuple_size
= PyTuple_Size (value_obj
);
222 error (_("Tuple value with RGB must be of size 3."));
224 for (int i
= 0; i
< 3; ++i
)
226 PyObject
*item
= PyTuple_GetItem (value_obj
, i
);
227 if (!PyLong_Check (item
))
228 error (_("Item %d of an RGB tuple must be integer."), i
);
229 long item_value
= -1;
230 if (!gdb_py_int_as_long (item
, &item_value
))
232 if (item_value
< 0 || item_value
> UINT8_MAX
)
233 error (_("RGB item %ld is out of byte range."), item_value
);
234 rgb
[i
] = static_cast<uint8_t> (item_value
);
237 obj
->color
= ui_file_style::color (rgb
[0], rgb
[1], rgb
[2]);
239 else if (PyUnicode_Check (value_obj
))
241 gdb::unique_xmalloc_ptr
<char>
242 str (python_string_to_host_string (value_obj
));
245 obj
->color
= parse_var_color (str
.get());
247 if (colorspace_obj
!= nullptr
248 && colorspace
!= obj
->color
.colorspace ())
249 error (_("colorspace doesn't match to the value."));
252 error (_("value must be one of None, integer, tuple or str."));
254 catch (const gdb_exception
&except
)
256 return gdbpy_handle_gdb_exception (-1, except
);
264 colorpy_str (PyObject
*self
)
266 colorpy_object
*obj
= reinterpret_cast<colorpy_object
*> (self
);
268 return PyUnicode_FromString (obj
->color
.to_string ().c_str ());
271 /* Initialize the 'color' module. */
273 gdbpy_initialize_color (void)
275 for (auto & pair
: colorspace_constants
)
276 if (PyModule_AddIntConstant (gdb_module
, pair
.name
,
277 static_cast<long> (pair
.value
)) < 0)
280 colorpy_object_type
.tp_new
= PyType_GenericNew
;
281 return gdbpy_type_ready (&colorpy_object_type
, gdb_module
);
286 static PyMethodDef color_methods
[] =
288 { "escape_sequence", colorpy_escape_sequence
, METH_O
,
289 "escape_sequence (is_foreground) -> str.\n\
290 Return the ANSI escape sequence for this color.\n\
291 IS_FOREGROUND indicates whether this is a foreground or background color."},
295 PyTypeObject colorpy_object_type
=
297 PyVarObject_HEAD_INIT (nullptr, 0)
298 "gdb.Color", /*tp_name*/
299 sizeof (colorpy_object
), /*tp_basicsize*/
308 0, /*tp_as_sequence*/
312 colorpy_str
, /*tp_str*/
313 get_attr
, /*tp_getattro*/
316 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_BASETYPE
, /*tp_flags*/
317 "GDB color object", /* tp_doc */
320 0, /* tp_richcompare */
321 0, /* tp_weaklistoffset */
324 color_methods
, /* tp_methods */
329 0, /* tp_descr_get */
330 0, /* tp_descr_set */
331 0, /* tp_dictoffset */
332 colorpy_init
, /* tp_init */
336 GDBPY_INITIALIZE_FILE (gdbpy_initialize_color
);