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