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