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