osdata.c revision 1.3 1 1.1 christos /* Routines for handling XML generic OS data provided by target.
2 1.1 christos
3 1.3 christos Copyright (C) 2008-2015 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 "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.1 christos struct 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.1 christos {
50 1.1 christos struct osdata *osdata;
51 1.1 christos char *property_name;
52 1.1 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.1 christos void *user_data, VEC(gdb_xml_value_s) *attributes)
60 1.1 christos {
61 1.1 christos struct osdata_parsing_data *data = user_data;
62 1.1 christos char *type;
63 1.1 christos struct osdata *osdata;
64 1.1 christos
65 1.1 christos if (data->osdata)
66 1.1 christos gdb_xml_error (parser, _("Seen more than on osdata element"));
67 1.1 christos
68 1.1 christos type = xml_find_attribute (attributes, "type")->value;
69 1.3 christos osdata = XCNEW (struct osdata);
70 1.1 christos osdata->type = xstrdup (type);
71 1.1 christos data->osdata = osdata;
72 1.1 christos }
73 1.1 christos
74 1.1 christos /* Handle the start of a <item> element. */
75 1.1 christos
76 1.1 christos static void
77 1.1 christos osdata_start_item (struct gdb_xml_parser *parser,
78 1.1 christos const struct gdb_xml_element *element,
79 1.1 christos void *user_data, VEC(gdb_xml_value_s) *attributes)
80 1.1 christos {
81 1.1 christos struct osdata_parsing_data *data = user_data;
82 1.1 christos struct osdata_item item = { NULL };
83 1.1 christos
84 1.1 christos VEC_safe_push (osdata_item_s, data->osdata->items, &item);
85 1.1 christos }
86 1.1 christos
87 1.1 christos /* Handle the start of a <column> element. */
88 1.1 christos
89 1.1 christos static void
90 1.1 christos osdata_start_column (struct gdb_xml_parser *parser,
91 1.1 christos const struct gdb_xml_element *element,
92 1.1 christos void *user_data, VEC(gdb_xml_value_s) *attributes)
93 1.1 christos {
94 1.1 christos struct osdata_parsing_data *data = user_data;
95 1.1 christos const char *name = xml_find_attribute (attributes, "name")->value;
96 1.1 christos
97 1.1 christos data->property_name = xstrdup (name);
98 1.1 christos }
99 1.1 christos
100 1.1 christos /* Handle the end of a <column> element. */
101 1.1 christos
102 1.1 christos static void
103 1.1 christos osdata_end_column (struct gdb_xml_parser *parser,
104 1.1 christos const struct gdb_xml_element *element,
105 1.1 christos void *user_data, const char *body_text)
106 1.1 christos {
107 1.1 christos struct osdata_parsing_data *data = user_data;
108 1.1 christos struct osdata *osdata = data->osdata;
109 1.1 christos struct osdata_item *item = VEC_last (osdata_item_s, osdata->items);
110 1.1 christos struct osdata_column *col = VEC_safe_push (osdata_column_s,
111 1.1 christos item->columns, NULL);
112 1.1 christos
113 1.1 christos /* Transfer memory ownership. NAME was already strdup'ed. */
114 1.1 christos col->name = data->property_name;
115 1.1 christos col->value = xstrdup (body_text);
116 1.1 christos data->property_name = NULL;
117 1.1 christos }
118 1.1 christos
119 1.1 christos /* Discard the constructed osdata (if an error occurs). */
120 1.1 christos
121 1.1 christos static void
122 1.1 christos clear_parsing_data (void *p)
123 1.1 christos {
124 1.1 christos struct osdata_parsing_data *data = p;
125 1.1 christos
126 1.1 christos osdata_free (data->osdata);
127 1.1 christos data->osdata = NULL;
128 1.1 christos xfree (data->property_name);
129 1.1 christos data->property_name = NULL;
130 1.1 christos }
131 1.1 christos
132 1.1 christos /* The allowed elements and attributes for OS data object.
133 1.1 christos The root element is a <osdata>. */
134 1.1 christos
135 1.1 christos const struct gdb_xml_attribute column_attributes[] = {
136 1.1 christos { "name", GDB_XML_AF_NONE, NULL, NULL },
137 1.1 christos { NULL, GDB_XML_AF_NONE, NULL, NULL }
138 1.1 christos };
139 1.1 christos
140 1.1 christos const struct gdb_xml_element item_children[] = {
141 1.1 christos { "column", column_attributes, NULL,
142 1.1 christos GDB_XML_EF_REPEATABLE | GDB_XML_EF_OPTIONAL,
143 1.1 christos osdata_start_column, osdata_end_column },
144 1.1 christos { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
145 1.1 christos };
146 1.1 christos
147 1.1 christos const struct gdb_xml_attribute osdata_attributes[] = {
148 1.1 christos { "type", GDB_XML_AF_NONE, NULL, NULL },
149 1.1 christos { NULL, GDB_XML_AF_NONE, NULL, NULL }
150 1.1 christos };
151 1.1 christos
152 1.1 christos const struct gdb_xml_element osdata_children[] = {
153 1.1 christos { "item", NULL, item_children,
154 1.1 christos GDB_XML_EF_REPEATABLE | GDB_XML_EF_OPTIONAL,
155 1.1 christos osdata_start_item, NULL },
156 1.1 christos { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
157 1.1 christos };
158 1.1 christos
159 1.1 christos const struct gdb_xml_element osdata_elements[] = {
160 1.1 christos { "osdata", osdata_attributes, osdata_children,
161 1.1 christos GDB_XML_EF_NONE, osdata_start_osdata, NULL },
162 1.1 christos { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
163 1.1 christos };
164 1.1 christos
165 1.1 christos struct osdata *
166 1.1 christos osdata_parse (const char *xml)
167 1.1 christos {
168 1.1 christos struct cleanup *back_to;
169 1.1 christos struct osdata_parsing_data data = { NULL };
170 1.1 christos
171 1.1 christos back_to = make_cleanup (clear_parsing_data, &data);
172 1.1 christos
173 1.1 christos if (gdb_xml_parse_quick (_("osdata"), "osdata.dtd",
174 1.1 christos osdata_elements, xml, &data) == 0)
175 1.1 christos {
176 1.1 christos /* Parsed successfully, don't need to delete the result. */
177 1.1 christos discard_cleanups (back_to);
178 1.1 christos return data.osdata;
179 1.1 christos }
180 1.1 christos
181 1.1 christos do_cleanups (back_to);
182 1.1 christos return NULL;
183 1.1 christos }
184 1.1 christos #endif
185 1.1 christos
186 1.1 christos static void
187 1.1 christos osdata_item_clear (struct osdata_item *item)
188 1.1 christos {
189 1.1 christos if (item->columns != NULL)
190 1.1 christos {
191 1.1 christos struct osdata_column *col;
192 1.1 christos int ix;
193 1.1 christos
194 1.1 christos for (ix = 0;
195 1.1 christos VEC_iterate (osdata_column_s, item->columns,
196 1.1 christos ix, col);
197 1.1 christos ix++)
198 1.1 christos {
199 1.1 christos xfree (col->name);
200 1.1 christos xfree (col->value);
201 1.1 christos }
202 1.1 christos VEC_free (osdata_column_s, item->columns);
203 1.1 christos item->columns = NULL;
204 1.1 christos }
205 1.1 christos }
206 1.1 christos
207 1.1 christos void
208 1.1 christos osdata_free (struct osdata *osdata)
209 1.1 christos {
210 1.1 christos if (osdata == NULL)
211 1.1 christos return;
212 1.1 christos
213 1.1 christos if (osdata->items != NULL)
214 1.1 christos {
215 1.1 christos struct osdata_item *item;
216 1.1 christos int ix;
217 1.1 christos
218 1.1 christos for (ix = 0;
219 1.1 christos VEC_iterate (osdata_item_s, osdata->items,
220 1.1 christos ix, item);
221 1.1 christos ix++)
222 1.1 christos osdata_item_clear (item);
223 1.1 christos VEC_free (osdata_item_s, osdata->items);
224 1.1 christos }
225 1.1 christos
226 1.1 christos xfree (osdata);
227 1.1 christos }
228 1.1 christos
229 1.1 christos static void
230 1.1 christos osdata_free_cleanup (void *arg)
231 1.1 christos {
232 1.1 christos struct osdata *osdata = arg;
233 1.1 christos
234 1.1 christos osdata_free (osdata);
235 1.1 christos }
236 1.1 christos
237 1.1 christos struct cleanup *
238 1.1 christos make_cleanup_osdata_free (struct osdata *data)
239 1.1 christos {
240 1.1 christos return make_cleanup (osdata_free_cleanup, data);
241 1.1 christos }
242 1.1 christos
243 1.1 christos struct osdata *
244 1.1 christos get_osdata (const char *type)
245 1.1 christos {
246 1.1 christos struct osdata *osdata = NULL;
247 1.1 christos char *xml = target_get_osdata (type);
248 1.1 christos
249 1.1 christos if (xml)
250 1.1 christos {
251 1.1 christos struct cleanup *old_chain = make_cleanup (xfree, xml);
252 1.1 christos
253 1.1 christos if (xml[0] == '\0')
254 1.1 christos {
255 1.1 christos if (type)
256 1.1 christos warning (_("Empty data returned by target. Wrong osdata type?"));
257 1.1 christos else
258 1.1 christos warning (_("Empty type list returned by target. No type data?"));
259 1.1 christos }
260 1.1 christos else
261 1.1 christos osdata = osdata_parse (xml);
262 1.1 christos
263 1.1 christos do_cleanups (old_chain);
264 1.1 christos }
265 1.1 christos
266 1.1 christos if (!osdata)
267 1.1 christos error (_("Can not fetch data now."));
268 1.1 christos
269 1.1 christos return osdata;
270 1.1 christos }
271 1.1 christos
272 1.1 christos const char *
273 1.1 christos get_osdata_column (struct osdata_item *item, const char *name)
274 1.1 christos {
275 1.1 christos struct osdata_column *col;
276 1.1 christos int ix_cols;
277 1.1 christos
278 1.1 christos for (ix_cols = 0;
279 1.1 christos VEC_iterate (osdata_column_s, item->columns,
280 1.1 christos ix_cols, col);
281 1.1 christos ix_cols++)
282 1.1 christos if (strcmp (col->name, name) == 0)
283 1.1 christos return col->value;
284 1.1 christos
285 1.1 christos return NULL;
286 1.1 christos }
287 1.1 christos
288 1.1 christos void
289 1.1 christos info_osdata_command (char *type, int from_tty)
290 1.1 christos {
291 1.1 christos struct ui_out *uiout = current_uiout;
292 1.1 christos struct osdata *osdata = NULL;
293 1.1 christos struct osdata_item *last = NULL;
294 1.1 christos struct cleanup *old_chain;
295 1.1 christos int ncols = 0;
296 1.1 christos int nrows;
297 1.1 christos int col_to_skip = -1;
298 1.1 christos
299 1.1 christos osdata = get_osdata (type);
300 1.1 christos old_chain = make_cleanup_osdata_free (osdata);
301 1.1 christos
302 1.1 christos nrows = VEC_length (osdata_item_s, osdata->items);
303 1.1 christos
304 1.1 christos if (!type && nrows == 0)
305 1.1 christos error (_("Available types of OS data not reported."));
306 1.1 christos
307 1.1 christos if (!VEC_empty (osdata_item_s, osdata->items))
308 1.1 christos {
309 1.1 christos last = VEC_last (osdata_item_s, osdata->items);
310 1.1 christos if (last->columns)
311 1.1 christos ncols = VEC_length (osdata_column_s, last->columns);
312 1.1 christos
313 1.1 christos /* As a special case, scan the listing of available data types
314 1.1 christos for a column named "Title", and only include it with MI
315 1.1 christos output; this column's normal use is for titles for interface
316 1.1 christos elements like menus, and it clutters up CLI output. */
317 1.1 christos if (!type && !ui_out_is_mi_like_p (uiout))
318 1.1 christos {
319 1.1 christos struct osdata_column *col;
320 1.1 christos int ix;
321 1.1 christos
322 1.1 christos for (ix = 0;
323 1.1 christos VEC_iterate (osdata_column_s, last->columns, ix, col);
324 1.1 christos ix++)
325 1.1 christos {
326 1.1 christos if (strcmp (col->name, "Title") == 0)
327 1.1 christos col_to_skip = ix;
328 1.1 christos }
329 1.1 christos /* Be sure to reduce the total column count, otherwise
330 1.1 christos internal errors ensue. */
331 1.1 christos if (col_to_skip >= 0)
332 1.1 christos --ncols;
333 1.1 christos }
334 1.1 christos }
335 1.1 christos
336 1.1 christos make_cleanup_ui_out_table_begin_end (uiout, ncols, nrows,
337 1.1 christos "OSDataTable");
338 1.1 christos
339 1.1 christos /* With no columns/items, we just output an empty table, but we
340 1.1 christos still output the table. This matters for MI. */
341 1.1 christos if (ncols == 0)
342 1.1 christos {
343 1.1 christos do_cleanups (old_chain);
344 1.1 christos return;
345 1.1 christos }
346 1.1 christos
347 1.1 christos if (last && last->columns)
348 1.1 christos {
349 1.1 christos struct osdata_column *col;
350 1.1 christos int ix;
351 1.1 christos
352 1.1 christos for (ix = 0;
353 1.1 christos VEC_iterate (osdata_column_s, last->columns,
354 1.1 christos ix, col);
355 1.1 christos ix++)
356 1.1 christos {
357 1.1 christos char col_name[32];
358 1.1 christos
359 1.1 christos if (ix == col_to_skip)
360 1.1 christos continue;
361 1.1 christos
362 1.1 christos snprintf (col_name, 32, "col%d", ix);
363 1.1 christos ui_out_table_header (uiout, 10, ui_left,
364 1.1 christos col_name, col->name);
365 1.1 christos }
366 1.1 christos }
367 1.1 christos
368 1.1 christos ui_out_table_body (uiout);
369 1.1 christos
370 1.1 christos if (nrows != 0)
371 1.1 christos {
372 1.1 christos struct osdata_item *item;
373 1.1 christos int ix_items;
374 1.1 christos
375 1.1 christos for (ix_items = 0;
376 1.1 christos VEC_iterate (osdata_item_s, osdata->items,
377 1.1 christos ix_items, item);
378 1.1 christos ix_items++)
379 1.1 christos {
380 1.1 christos struct cleanup *old_chain;
381 1.1 christos int ix_cols;
382 1.1 christos struct osdata_column *col;
383 1.1 christos
384 1.1 christos old_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "item");
385 1.1 christos
386 1.1 christos for (ix_cols = 0;
387 1.1 christos VEC_iterate (osdata_column_s, item->columns,
388 1.1 christos ix_cols, col);
389 1.1 christos ix_cols++)
390 1.1 christos {
391 1.1 christos char col_name[32];
392 1.1 christos
393 1.1 christos if (ix_cols == col_to_skip)
394 1.1 christos continue;
395 1.1 christos
396 1.1 christos snprintf (col_name, 32, "col%d", ix_cols);
397 1.1 christos ui_out_field_string (uiout, col_name, col->value);
398 1.1 christos }
399 1.1 christos
400 1.1 christos do_cleanups (old_chain);
401 1.1 christos
402 1.1 christos ui_out_text (uiout, "\n");
403 1.1 christos }
404 1.1 christos }
405 1.1 christos
406 1.1 christos do_cleanups (old_chain);
407 1.1 christos }
408 1.1 christos
409 1.1 christos extern initialize_file_ftype _initialize_osdata; /* -Wmissing-prototypes */
410 1.1 christos
411 1.1 christos void
412 1.1 christos _initialize_osdata (void)
413 1.1 christos {
414 1.1 christos add_info ("os", info_osdata_command,
415 1.1 christos _("Show OS data ARG."));
416 1.1 christos }
417