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