Home | History | Annotate | Line # | Download | only in gdb
osdata.c revision 1.7
      1 /* Routines for handling XML generic OS data provided by target.
      2 
      3    Copyright (C) 2008-2017 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 "ui-out.h"
     26 #include "gdbcmd.h"
     27 
     28 #if !defined(HAVE_LIBEXPAT)
     29 
     30 struct osdata *
     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 
     47 /* Internal parsing data passed to all XML callbacks.  */
     48 struct osdata_parsing_data
     49   {
     50     struct osdata *osdata;
     51     char *property_name;
     52   };
     53 
     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 {
     61   struct osdata_parsing_data *data = (struct osdata_parsing_data *) user_data;
     62   char *type;
     63   struct osdata *osdata;
     64 
     65   if (data->osdata)
     66     gdb_xml_error (parser, _("Seen more than on osdata element"));
     67 
     68   type = (char *) xml_find_attribute (attributes, "type")->value;
     69   osdata = XCNEW (struct osdata);
     70   osdata->type = xstrdup (type);
     71   data->osdata = osdata;
     72 }
     73 
     74 /* Handle the start of a <item> element.  */
     75 
     76 static void
     77 osdata_start_item (struct gdb_xml_parser *parser,
     78                   const struct gdb_xml_element *element,
     79                   void *user_data, VEC(gdb_xml_value_s) *attributes)
     80 {
     81   struct osdata_parsing_data *data = (struct osdata_parsing_data *) user_data;
     82   struct osdata_item item = { NULL };
     83 
     84   VEC_safe_push (osdata_item_s, data->osdata->items, &item);
     85 }
     86 
     87 /* Handle the start of a <column> element.  */
     88 
     89 static void
     90 osdata_start_column (struct gdb_xml_parser *parser,
     91                     const struct gdb_xml_element *element,
     92                     void *user_data, VEC(gdb_xml_value_s) *attributes)
     93 {
     94   struct osdata_parsing_data *data = (struct osdata_parsing_data *) user_data;
     95   const char *name
     96     = (const char *) 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 = (struct osdata_parsing_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 = (struct osdata_parsing_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 = (struct 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 (const char *type)
    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   if (type == NULL)
    301     type = "";
    302 
    303   osdata = get_osdata (type);
    304   old_chain = make_cleanup_osdata_free (osdata);
    305 
    306   nrows = VEC_length (osdata_item_s, osdata->items);
    307 
    308   if (*type == '\0' && nrows == 0)
    309     error (_("Available types of OS data not reported."));
    310 
    311   if (!VEC_empty (osdata_item_s, osdata->items))
    312     {
    313       last = VEC_last (osdata_item_s, osdata->items);
    314       if (last->columns)
    315         ncols = VEC_length (osdata_column_s, last->columns);
    316 
    317       /* As a special case, scan the listing of available data types
    318 	 for a column named "Title", and only include it with MI
    319 	 output; this column's normal use is for titles for interface
    320 	 elements like menus, and it clutters up CLI output.  */
    321       if (*type == '\0' && !uiout->is_mi_like_p ())
    322 	{
    323 	  struct osdata_column *col;
    324 	  int ix;
    325 
    326 	  for (ix = 0;
    327 	       VEC_iterate (osdata_column_s, last->columns, ix, col);
    328 	       ix++)
    329 	    {
    330 	      if (strcmp (col->name, "Title") == 0)
    331 		col_to_skip = ix;
    332 	    }
    333 	  /* Be sure to reduce the total column count, otherwise
    334 	     internal errors ensue.  */
    335 	  if (col_to_skip >= 0)
    336 	    --ncols;
    337 	}
    338     }
    339 
    340   make_cleanup_ui_out_table_begin_end (uiout, ncols, nrows,
    341 				       "OSDataTable");
    342 
    343   /* With no columns/items, we just output an empty table, but we
    344      still output the table.  This matters for MI.  */
    345   if (ncols == 0)
    346     {
    347       do_cleanups (old_chain);
    348       return;
    349     }
    350 
    351   if (last && last->columns)
    352     {
    353       struct osdata_column *col;
    354       int ix;
    355 
    356       for (ix = 0;
    357           VEC_iterate (osdata_column_s, last->columns,
    358                        ix, col);
    359           ix++)
    360 	{
    361 	  char col_name[32];
    362 
    363 	  if (ix == col_to_skip)
    364 	    continue;
    365 
    366 	  snprintf (col_name, 32, "col%d", ix);
    367 	  uiout->table_header (10, ui_left,
    368 			       col_name, col->name);
    369         }
    370     }
    371 
    372   uiout->table_body ();
    373 
    374   if (nrows != 0)
    375     {
    376       struct osdata_item *item;
    377       int ix_items;
    378 
    379       for (ix_items = 0;
    380           VEC_iterate (osdata_item_s, osdata->items,
    381                        ix_items, item);
    382           ix_items++)
    383        {
    384          struct cleanup *old_chain;
    385          int ix_cols;
    386          struct osdata_column *col;
    387 
    388          old_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "item");
    389 
    390          for (ix_cols = 0;
    391               VEC_iterate (osdata_column_s, item->columns,
    392                            ix_cols, col);
    393               ix_cols++)
    394 	   {
    395 	     char col_name[32];
    396 
    397 	     if (ix_cols == col_to_skip)
    398 	       continue;
    399 
    400 	     snprintf (col_name, 32, "col%d", ix_cols);
    401 	     uiout->field_string (col_name, col->value);
    402 	   }
    403 
    404          do_cleanups (old_chain);
    405 
    406          uiout->text ("\n");
    407        }
    408     }
    409 
    410   do_cleanups (old_chain);
    411 }
    412 
    413 static void
    414 info_osdata_command (char *arg, int from_tty)
    415 {
    416   info_osdata (arg);
    417 }
    418 
    419 extern initialize_file_ftype _initialize_osdata; /* -Wmissing-prototypes */
    420 
    421 void
    422 _initialize_osdata (void)
    423 {
    424   add_info ("os", info_osdata_command,
    425            _("Show OS data ARG."));
    426 }
    427