osdata.c revision 1.10 1 1.1 christos /* Routines for handling XML generic OS data provided by target.
2 1.1 christos
3 1.10 christos Copyright (C) 2008-2023 Free Software Foundation, Inc.
4 1.1 christos
5 1.1 christos This file is part of GDB.
6 1.1 christos
7 1.1 christos This program is free software; you can redistribute it and/or modify
8 1.1 christos it under the terms of the GNU General Public License as published by
9 1.1 christos the Free Software Foundation; either version 3 of the License, or
10 1.1 christos (at your option) any later version.
11 1.1 christos
12 1.1 christos This program is distributed in the hope that it will be useful,
13 1.1 christos but WITHOUT ANY WARRANTY; without even the implied warranty of
14 1.1 christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 1.1 christos GNU General Public License for more details.
16 1.1 christos
17 1.1 christos You should have received a copy of the GNU General Public License
18 1.1 christos along with this program. If not, see <http://www.gnu.org/licenses/>. */
19 1.1 christos
20 1.1 christos #include "defs.h"
21 1.1 christos #include "target.h"
22 1.1 christos #include "xml-support.h"
23 1.1 christos #include "osdata.h"
24 1.1 christos #include "ui-out.h"
25 1.1 christos #include "gdbcmd.h"
26 1.1 christos
27 1.1 christos #if !defined(HAVE_LIBEXPAT)
28 1.1 christos
29 1.8 christos std::unique_ptr<osdata>
30 1.1 christos osdata_parse (const char *xml)
31 1.1 christos {
32 1.1 christos static int have_warned;
33 1.1 christos
34 1.1 christos if (!have_warned)
35 1.1 christos {
36 1.1 christos have_warned = 1;
37 1.1 christos warning (_("Can not parse XML OS data; XML support was disabled "
38 1.10 christos "at compile time"));
39 1.1 christos }
40 1.1 christos
41 1.1 christos return NULL;
42 1.1 christos }
43 1.1 christos
44 1.1 christos #else /* HAVE_LIBEXPAT */
45 1.1 christos
46 1.1 christos /* Internal parsing data passed to all XML callbacks. */
47 1.1 christos struct osdata_parsing_data
48 1.8 christos {
49 1.8 christos std::unique_ptr<struct osdata> osdata;
50 1.8 christos std::string property_name;
51 1.8 christos };
52 1.1 christos
53 1.1 christos /* Handle the start of a <osdata> element. */
54 1.1 christos
55 1.1 christos static void
56 1.1 christos osdata_start_osdata (struct gdb_xml_parser *parser,
57 1.10 christos const struct gdb_xml_element *element,
58 1.10 christos void *user_data,
59 1.8 christos std::vector<gdb_xml_value> &attributes)
60 1.1 christos {
61 1.6 christos struct osdata_parsing_data *data = (struct osdata_parsing_data *) user_data;
62 1.1 christos
63 1.8 christos if (data->osdata != NULL)
64 1.1 christos gdb_xml_error (parser, _("Seen more than on osdata element"));
65 1.1 christos
66 1.8 christos char *type = (char *) xml_find_attribute (attributes, "type")->value.get ();
67 1.8 christos data->osdata.reset (new struct osdata (std::string (type)));
68 1.1 christos }
69 1.1 christos
70 1.1 christos /* Handle the start of a <item> element. */
71 1.1 christos
72 1.1 christos static void
73 1.1 christos osdata_start_item (struct gdb_xml_parser *parser,
74 1.10 christos const struct gdb_xml_element *element,
75 1.10 christos void *user_data,
76 1.8 christos std::vector<gdb_xml_value> &attributes)
77 1.1 christos {
78 1.6 christos struct osdata_parsing_data *data = (struct osdata_parsing_data *) user_data;
79 1.8 christos data->osdata->items.emplace_back ();
80 1.1 christos }
81 1.1 christos
82 1.1 christos /* Handle the start of a <column> element. */
83 1.1 christos
84 1.1 christos static void
85 1.1 christos osdata_start_column (struct gdb_xml_parser *parser,
86 1.10 christos const struct gdb_xml_element *element,
87 1.10 christos void *user_data,
88 1.8 christos std::vector<gdb_xml_value> &attributes)
89 1.1 christos {
90 1.6 christos struct osdata_parsing_data *data = (struct osdata_parsing_data *) user_data;
91 1.6 christos const char *name
92 1.8 christos = (const char *) xml_find_attribute (attributes, "name")->value.get ();
93 1.1 christos
94 1.8 christos data->property_name.assign (name);
95 1.1 christos }
96 1.1 christos
97 1.1 christos /* Handle the end of a <column> element. */
98 1.1 christos
99 1.1 christos static void
100 1.1 christos osdata_end_column (struct gdb_xml_parser *parser,
101 1.10 christos const struct gdb_xml_element *element,
102 1.10 christos void *user_data, const char *body_text)
103 1.1 christos {
104 1.8 christos osdata_parsing_data *data = (struct osdata_parsing_data *) user_data;
105 1.8 christos struct osdata *osdata = data->osdata.get ();
106 1.8 christos osdata_item &item = osdata->items.back ();
107 1.1 christos
108 1.8 christos item.columns.emplace_back (std::move (data->property_name),
109 1.8 christos std::string (body_text));
110 1.1 christos }
111 1.1 christos
112 1.1 christos /* The allowed elements and attributes for OS data object.
113 1.1 christos The root element is a <osdata>. */
114 1.1 christos
115 1.1 christos const struct gdb_xml_attribute column_attributes[] = {
116 1.1 christos { "name", GDB_XML_AF_NONE, NULL, NULL },
117 1.1 christos { NULL, GDB_XML_AF_NONE, NULL, NULL }
118 1.1 christos };
119 1.1 christos
120 1.1 christos const struct gdb_xml_element item_children[] = {
121 1.1 christos { "column", column_attributes, NULL,
122 1.1 christos GDB_XML_EF_REPEATABLE | GDB_XML_EF_OPTIONAL,
123 1.1 christos osdata_start_column, osdata_end_column },
124 1.1 christos { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
125 1.1 christos };
126 1.1 christos
127 1.1 christos const struct gdb_xml_attribute osdata_attributes[] = {
128 1.1 christos { "type", GDB_XML_AF_NONE, NULL, NULL },
129 1.1 christos { NULL, GDB_XML_AF_NONE, NULL, NULL }
130 1.1 christos };
131 1.1 christos
132 1.1 christos const struct gdb_xml_element osdata_children[] = {
133 1.1 christos { "item", NULL, item_children,
134 1.1 christos GDB_XML_EF_REPEATABLE | GDB_XML_EF_OPTIONAL,
135 1.1 christos osdata_start_item, NULL },
136 1.1 christos { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
137 1.1 christos };
138 1.1 christos
139 1.1 christos const struct gdb_xml_element osdata_elements[] = {
140 1.1 christos { "osdata", osdata_attributes, osdata_children,
141 1.1 christos GDB_XML_EF_NONE, osdata_start_osdata, NULL },
142 1.1 christos { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
143 1.1 christos };
144 1.1 christos
145 1.8 christos std::unique_ptr<osdata>
146 1.1 christos osdata_parse (const char *xml)
147 1.1 christos {
148 1.8 christos osdata_parsing_data data;
149 1.1 christos
150 1.1 christos if (gdb_xml_parse_quick (_("osdata"), "osdata.dtd",
151 1.1 christos osdata_elements, xml, &data) == 0)
152 1.1 christos {
153 1.1 christos /* Parsed successfully, don't need to delete the result. */
154 1.8 christos return std::move (data.osdata);
155 1.1 christos }
156 1.1 christos
157 1.1 christos return NULL;
158 1.1 christos }
159 1.1 christos #endif
160 1.1 christos
161 1.8 christos std::unique_ptr<osdata>
162 1.1 christos get_osdata (const char *type)
163 1.1 christos {
164 1.8 christos std::unique_ptr<osdata> osdata;
165 1.8 christos gdb::optional<gdb::char_vector> xml = target_get_osdata (type);
166 1.1 christos
167 1.1 christos if (xml)
168 1.1 christos {
169 1.8 christos if ((*xml)[0] == '\0')
170 1.1 christos {
171 1.1 christos if (type)
172 1.1 christos warning (_("Empty data returned by target. Wrong osdata type?"));
173 1.1 christos else
174 1.1 christos warning (_("Empty type list returned by target. No type data?"));
175 1.1 christos }
176 1.1 christos else
177 1.8 christos osdata = osdata_parse (xml->data ());
178 1.1 christos }
179 1.1 christos
180 1.8 christos if (osdata == NULL)
181 1.1 christos error (_("Can not fetch data now."));
182 1.1 christos
183 1.1 christos return osdata;
184 1.1 christos }
185 1.1 christos
186 1.8 christos const std::string *
187 1.8 christos get_osdata_column (const osdata_item &item, const char *name)
188 1.1 christos {
189 1.8 christos for (const osdata_column &col : item.columns)
190 1.8 christos if (col.name == name)
191 1.8 christos return &col.value;
192 1.1 christos
193 1.1 christos return NULL;
194 1.1 christos }
195 1.1 christos
196 1.1 christos void
197 1.7 christos info_osdata (const char *type)
198 1.1 christos {
199 1.1 christos struct ui_out *uiout = current_uiout;
200 1.1 christos struct osdata_item *last = NULL;
201 1.1 christos int ncols = 0;
202 1.1 christos int col_to_skip = -1;
203 1.1 christos
204 1.7 christos if (type == NULL)
205 1.7 christos type = "";
206 1.7 christos
207 1.8 christos std::unique_ptr<osdata> osdata = get_osdata (type);
208 1.1 christos
209 1.8 christos int nrows = osdata->items.size ();
210 1.1 christos
211 1.7 christos if (*type == '\0' && nrows == 0)
212 1.1 christos error (_("Available types of OS data not reported."));
213 1.1 christos
214 1.8 christos if (!osdata->items.empty ())
215 1.1 christos {
216 1.8 christos last = &osdata->items.back ();
217 1.8 christos ncols = last->columns.size ();
218 1.1 christos
219 1.1 christos /* As a special case, scan the listing of available data types
220 1.1 christos for a column named "Title", and only include it with MI
221 1.1 christos output; this column's normal use is for titles for interface
222 1.1 christos elements like menus, and it clutters up CLI output. */
223 1.7 christos if (*type == '\0' && !uiout->is_mi_like_p ())
224 1.1 christos {
225 1.8 christos for (int ix = 0; ix < last->columns.size (); ix++)
226 1.1 christos {
227 1.8 christos if (last->columns[ix].name == "Title")
228 1.1 christos col_to_skip = ix;
229 1.1 christos }
230 1.1 christos /* Be sure to reduce the total column count, otherwise
231 1.1 christos internal errors ensue. */
232 1.1 christos if (col_to_skip >= 0)
233 1.1 christos --ncols;
234 1.1 christos }
235 1.1 christos }
236 1.1 christos
237 1.8 christos ui_out_emit_table table_emitter (uiout, ncols, nrows, "OSDataTable");
238 1.1 christos
239 1.1 christos /* With no columns/items, we just output an empty table, but we
240 1.1 christos still output the table. This matters for MI. */
241 1.1 christos if (ncols == 0)
242 1.8 christos return;
243 1.1 christos
244 1.8 christos if (last != NULL && !last->columns.empty ())
245 1.1 christos {
246 1.8 christos for (int ix = 0; ix < last->columns.size (); ix++)
247 1.1 christos {
248 1.1 christos char col_name[32];
249 1.1 christos
250 1.1 christos if (ix == col_to_skip)
251 1.1 christos continue;
252 1.1 christos
253 1.1 christos snprintf (col_name, 32, "col%d", ix);
254 1.7 christos uiout->table_header (10, ui_left,
255 1.8 christos col_name, last->columns[ix].name.c_str ());
256 1.10 christos }
257 1.1 christos }
258 1.1 christos
259 1.7 christos uiout->table_body ();
260 1.1 christos
261 1.1 christos if (nrows != 0)
262 1.1 christos {
263 1.8 christos for (const osdata_item &item : osdata->items)
264 1.8 christos {
265 1.8 christos {
266 1.8 christos ui_out_emit_tuple tuple_emitter (uiout, "item");
267 1.1 christos
268 1.8 christos for (int ix_cols = 0; ix_cols < item.columns.size (); ix_cols++)
269 1.8 christos {
270 1.8 christos char col_name[32];
271 1.8 christos
272 1.8 christos if (ix_cols == col_to_skip)
273 1.8 christos continue;
274 1.8 christos
275 1.8 christos snprintf (col_name, 32, "col%d", ix_cols);
276 1.10 christos uiout->field_string (col_name, item.columns[ix_cols].value);
277 1.8 christos }
278 1.8 christos }
279 1.1 christos
280 1.10 christos uiout->text ("\n");
281 1.1 christos }
282 1.1 christos }
283 1.1 christos }
284 1.1 christos
285 1.7 christos static void
286 1.8 christos info_osdata_command (const char *arg, int from_tty)
287 1.7 christos {
288 1.7 christos info_osdata (arg);
289 1.7 christos }
290 1.7 christos
291 1.9 christos void _initialize_osdata ();
292 1.1 christos void
293 1.9 christos _initialize_osdata ()
294 1.1 christos {
295 1.1 christos add_info ("os", info_osdata_command,
296 1.10 christos _("Show OS data ARG."));
297 1.1 christos }
298