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