Home | History | Annotate | Line # | Download | only in mi
mi-parse.c revision 1.1
      1  1.1  christos /* MI Command Set - MI parser.
      2  1.1  christos 
      3  1.1  christos    Copyright (C) 2000-2014 Free Software Foundation, Inc.
      4  1.1  christos 
      5  1.1  christos    Contributed by Cygnus Solutions (a Red Hat company).
      6  1.1  christos 
      7  1.1  christos    This file is part of GDB.
      8  1.1  christos 
      9  1.1  christos    This program is free software; you can redistribute it and/or modify
     10  1.1  christos    it under the terms of the GNU General Public License as published by
     11  1.1  christos    the Free Software Foundation; either version 3 of the License, or
     12  1.1  christos    (at your option) any later version.
     13  1.1  christos 
     14  1.1  christos    This program is distributed in the hope that it will be useful,
     15  1.1  christos    but WITHOUT ANY WARRANTY; without even the implied warranty of
     16  1.1  christos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17  1.1  christos    GNU General Public License for more details.
     18  1.1  christos 
     19  1.1  christos    You should have received a copy of the GNU General Public License
     20  1.1  christos    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
     21  1.1  christos 
     22  1.1  christos #include "defs.h"
     23  1.1  christos #include "mi-cmds.h"
     24  1.1  christos #include "mi-parse.h"
     25  1.1  christos #include "charset.h"
     26  1.1  christos 
     27  1.1  christos #include <ctype.h>
     28  1.1  christos #include <string.h>
     29  1.1  christos #include "cli/cli-utils.h"
     30  1.1  christos #include "language.h"
     31  1.1  christos 
     32  1.1  christos static const char mi_no_values[] = "--no-values";
     33  1.1  christos static const char mi_simple_values[] = "--simple-values";
     34  1.1  christos static const char mi_all_values[] = "--all-values";
     35  1.1  christos 
     36  1.1  christos /* Like parse_escape, but leave the results as a host char, not a
     37  1.1  christos    target char.  */
     38  1.1  christos 
     39  1.1  christos static int
     40  1.1  christos mi_parse_escape (const char **string_ptr)
     41  1.1  christos {
     42  1.1  christos   int c = *(*string_ptr)++;
     43  1.1  christos 
     44  1.1  christos   switch (c)
     45  1.1  christos     {
     46  1.1  christos       case '\n':
     47  1.1  christos 	return -2;
     48  1.1  christos       case 0:
     49  1.1  christos 	(*string_ptr)--;
     50  1.1  christos 	return 0;
     51  1.1  christos 
     52  1.1  christos       case '0':
     53  1.1  christos       case '1':
     54  1.1  christos       case '2':
     55  1.1  christos       case '3':
     56  1.1  christos       case '4':
     57  1.1  christos       case '5':
     58  1.1  christos       case '6':
     59  1.1  christos       case '7':
     60  1.1  christos 	{
     61  1.1  christos 	  int i = host_hex_value (c);
     62  1.1  christos 	  int count = 0;
     63  1.1  christos 
     64  1.1  christos 	  while (++count < 3)
     65  1.1  christos 	    {
     66  1.1  christos 	      c = (**string_ptr);
     67  1.1  christos 	      if (isdigit (c) && c != '8' && c != '9')
     68  1.1  christos 		{
     69  1.1  christos 		  (*string_ptr)++;
     70  1.1  christos 		  i *= 8;
     71  1.1  christos 		  i += host_hex_value (c);
     72  1.1  christos 		}
     73  1.1  christos 	      else
     74  1.1  christos 		{
     75  1.1  christos 		  break;
     76  1.1  christos 		}
     77  1.1  christos 	    }
     78  1.1  christos 	  return i;
     79  1.1  christos 	}
     80  1.1  christos 
     81  1.1  christos     case 'a':
     82  1.1  christos       c = '\a';
     83  1.1  christos       break;
     84  1.1  christos     case 'b':
     85  1.1  christos       c = '\b';
     86  1.1  christos       break;
     87  1.1  christos     case 'f':
     88  1.1  christos       c = '\f';
     89  1.1  christos       break;
     90  1.1  christos     case 'n':
     91  1.1  christos       c = '\n';
     92  1.1  christos       break;
     93  1.1  christos     case 'r':
     94  1.1  christos       c = '\r';
     95  1.1  christos       break;
     96  1.1  christos     case 't':
     97  1.1  christos       c = '\t';
     98  1.1  christos       break;
     99  1.1  christos     case 'v':
    100  1.1  christos       c = '\v';
    101  1.1  christos       break;
    102  1.1  christos 
    103  1.1  christos     default:
    104  1.1  christos       break;
    105  1.1  christos     }
    106  1.1  christos 
    107  1.1  christos   return c;
    108  1.1  christos }
    109  1.1  christos 
    110  1.1  christos static void
    111  1.1  christos mi_parse_argv (const char *args, struct mi_parse *parse)
    112  1.1  christos {
    113  1.1  christos   const char *chp = args;
    114  1.1  christos   int argc = 0;
    115  1.1  christos   char **argv = xmalloc ((argc + 1) * sizeof (char *));
    116  1.1  christos 
    117  1.1  christos   argv[argc] = NULL;
    118  1.1  christos   while (1)
    119  1.1  christos     {
    120  1.1  christos       char *arg;
    121  1.1  christos 
    122  1.1  christos       /* Skip leading white space.  */
    123  1.1  christos       chp = skip_spaces_const (chp);
    124  1.1  christos       /* Three possibilities: EOF, quoted string, or other text. */
    125  1.1  christos       switch (*chp)
    126  1.1  christos 	{
    127  1.1  christos 	case '\0':
    128  1.1  christos 	  parse->argv = argv;
    129  1.1  christos 	  parse->argc = argc;
    130  1.1  christos 	  return;
    131  1.1  christos 	case '"':
    132  1.1  christos 	  {
    133  1.1  christos 	    /* A quoted string.  */
    134  1.1  christos 	    int len;
    135  1.1  christos 	    const char *start = chp + 1;
    136  1.1  christos 
    137  1.1  christos 	    /* Determine the buffer size.  */
    138  1.1  christos 	    chp = start;
    139  1.1  christos 	    len = 0;
    140  1.1  christos 	    while (*chp != '\0' && *chp != '"')
    141  1.1  christos 	      {
    142  1.1  christos 		if (*chp == '\\')
    143  1.1  christos 		  {
    144  1.1  christos 		    chp++;
    145  1.1  christos 		    if (mi_parse_escape (&chp) <= 0)
    146  1.1  christos 		      {
    147  1.1  christos 			/* Do not allow split lines or "\000".  */
    148  1.1  christos 			freeargv (argv);
    149  1.1  christos 			return;
    150  1.1  christos 		      }
    151  1.1  christos 		  }
    152  1.1  christos 		else
    153  1.1  christos 		  chp++;
    154  1.1  christos 		len++;
    155  1.1  christos 	      }
    156  1.1  christos 	    /* Insist on a closing quote.  */
    157  1.1  christos 	    if (*chp != '"')
    158  1.1  christos 	      {
    159  1.1  christos 		freeargv (argv);
    160  1.1  christos 		return;
    161  1.1  christos 	      }
    162  1.1  christos 	    /* Insist on trailing white space.  */
    163  1.1  christos 	    if (chp[1] != '\0' && !isspace (chp[1]))
    164  1.1  christos 	      {
    165  1.1  christos 		freeargv (argv);
    166  1.1  christos 		return;
    167  1.1  christos 	      }
    168  1.1  christos 	    /* Create the buffer and copy characters in.  */
    169  1.1  christos 	    arg = xmalloc ((len + 1) * sizeof (char));
    170  1.1  christos 	    chp = start;
    171  1.1  christos 	    len = 0;
    172  1.1  christos 	    while (*chp != '\0' && *chp != '"')
    173  1.1  christos 	      {
    174  1.1  christos 		if (*chp == '\\')
    175  1.1  christos 		  {
    176  1.1  christos 		    chp++;
    177  1.1  christos 		    arg[len] = mi_parse_escape (&chp);
    178  1.1  christos 		  }
    179  1.1  christos 		else
    180  1.1  christos 		  arg[len] = *chp++;
    181  1.1  christos 		len++;
    182  1.1  christos 	      }
    183  1.1  christos 	    arg[len] = '\0';
    184  1.1  christos 	    chp++;		/* That closing quote.  */
    185  1.1  christos 	    break;
    186  1.1  christos 	  }
    187  1.1  christos 	default:
    188  1.1  christos 	  {
    189  1.1  christos 	    /* An unquoted string.  Accumulate all non-blank
    190  1.1  christos 	       characters into a buffer.  */
    191  1.1  christos 	    int len;
    192  1.1  christos 	    const char *start = chp;
    193  1.1  christos 
    194  1.1  christos 	    while (*chp != '\0' && !isspace (*chp))
    195  1.1  christos 	      {
    196  1.1  christos 		chp++;
    197  1.1  christos 	      }
    198  1.1  christos 	    len = chp - start;
    199  1.1  christos 	    arg = xmalloc ((len + 1) * sizeof (char));
    200  1.1  christos 	    strncpy (arg, start, len);
    201  1.1  christos 	    arg[len] = '\0';
    202  1.1  christos 	    break;
    203  1.1  christos 	  }
    204  1.1  christos 	}
    205  1.1  christos       /* Append arg to argv.  */
    206  1.1  christos       argv = xrealloc (argv, (argc + 2) * sizeof (char *));
    207  1.1  christos       argv[argc++] = arg;
    208  1.1  christos       argv[argc] = NULL;
    209  1.1  christos     }
    210  1.1  christos }
    211  1.1  christos 
    212  1.1  christos void
    213  1.1  christos mi_parse_free (struct mi_parse *parse)
    214  1.1  christos {
    215  1.1  christos   if (parse == NULL)
    216  1.1  christos     return;
    217  1.1  christos   if (parse->command != NULL)
    218  1.1  christos     xfree (parse->command);
    219  1.1  christos   if (parse->token != NULL)
    220  1.1  christos     xfree (parse->token);
    221  1.1  christos   if (parse->args != NULL)
    222  1.1  christos     xfree (parse->args);
    223  1.1  christos   if (parse->argv != NULL)
    224  1.1  christos     freeargv (parse->argv);
    225  1.1  christos   xfree (parse);
    226  1.1  christos }
    227  1.1  christos 
    228  1.1  christos /* A cleanup that calls mi_parse_free.  */
    229  1.1  christos 
    230  1.1  christos static void
    231  1.1  christos mi_parse_cleanup (void *arg)
    232  1.1  christos {
    233  1.1  christos   mi_parse_free (arg);
    234  1.1  christos }
    235  1.1  christos 
    236  1.1  christos struct mi_parse *
    237  1.1  christos mi_parse (const char *cmd, char **token)
    238  1.1  christos {
    239  1.1  christos   const char *chp;
    240  1.1  christos   struct mi_parse *parse = XMALLOC (struct mi_parse);
    241  1.1  christos   struct cleanup *cleanup;
    242  1.1  christos 
    243  1.1  christos   memset (parse, 0, sizeof (*parse));
    244  1.1  christos   parse->all = 0;
    245  1.1  christos   parse->thread_group = -1;
    246  1.1  christos   parse->thread = -1;
    247  1.1  christos   parse->frame = -1;
    248  1.1  christos   parse->language = language_unknown;
    249  1.1  christos 
    250  1.1  christos   cleanup = make_cleanup (mi_parse_cleanup, parse);
    251  1.1  christos 
    252  1.1  christos   /* Before starting, skip leading white space.  */
    253  1.1  christos   cmd = skip_spaces_const (cmd);
    254  1.1  christos 
    255  1.1  christos   /* Find/skip any token and then extract it.  */
    256  1.1  christos   for (chp = cmd; *chp >= '0' && *chp <= '9'; chp++)
    257  1.1  christos     ;
    258  1.1  christos   *token = xmalloc (chp - cmd + 1);
    259  1.1  christos   memcpy (*token, cmd, (chp - cmd));
    260  1.1  christos   (*token)[chp - cmd] = '\0';
    261  1.1  christos 
    262  1.1  christos   /* This wasn't a real MI command.  Return it as a CLI_COMMAND.  */
    263  1.1  christos   if (*chp != '-')
    264  1.1  christos     {
    265  1.1  christos       chp = skip_spaces_const (chp);
    266  1.1  christos       parse->command = xstrdup (chp);
    267  1.1  christos       parse->op = CLI_COMMAND;
    268  1.1  christos 
    269  1.1  christos       discard_cleanups (cleanup);
    270  1.1  christos 
    271  1.1  christos       return parse;
    272  1.1  christos     }
    273  1.1  christos 
    274  1.1  christos   /* Extract the command.  */
    275  1.1  christos   {
    276  1.1  christos     const char *tmp = chp + 1;	/* discard ``-'' */
    277  1.1  christos 
    278  1.1  christos     for (; *chp && !isspace (*chp); chp++)
    279  1.1  christos       ;
    280  1.1  christos     parse->command = xmalloc (chp - tmp + 1);
    281  1.1  christos     memcpy (parse->command, tmp, chp - tmp);
    282  1.1  christos     parse->command[chp - tmp] = '\0';
    283  1.1  christos   }
    284  1.1  christos 
    285  1.1  christos   /* Find the command in the MI table.  */
    286  1.1  christos   parse->cmd = mi_lookup (parse->command);
    287  1.1  christos   if (parse->cmd == NULL)
    288  1.1  christos     throw_error (UNDEFINED_COMMAND_ERROR,
    289  1.1  christos 		 _("Undefined MI command: %s"), parse->command);
    290  1.1  christos 
    291  1.1  christos   /* Skip white space following the command.  */
    292  1.1  christos   chp = skip_spaces_const (chp);
    293  1.1  christos 
    294  1.1  christos   /* Parse the --thread and --frame options, if present.  At present,
    295  1.1  christos      some important commands, like '-break-*' are implemented by
    296  1.1  christos      forwarding to the CLI layer directly.  We want to parse --thread
    297  1.1  christos      and --frame here, so as not to leave those option in the string
    298  1.1  christos      that will be passed to CLI.
    299  1.1  christos 
    300  1.1  christos      Same for the --language option.  */
    301  1.1  christos 
    302  1.1  christos   for (;;)
    303  1.1  christos     {
    304  1.1  christos       const char *option;
    305  1.1  christos       size_t as = sizeof ("--all ") - 1;
    306  1.1  christos       size_t tgs = sizeof ("--thread-group ") - 1;
    307  1.1  christos       size_t ts = sizeof ("--thread ") - 1;
    308  1.1  christos       size_t fs = sizeof ("--frame ") - 1;
    309  1.1  christos       size_t ls = sizeof ("--language ") - 1;
    310  1.1  christos 
    311  1.1  christos       if (strncmp (chp, "--all ", as) == 0)
    312  1.1  christos 	{
    313  1.1  christos 	  parse->all = 1;
    314  1.1  christos 	  chp += as;
    315  1.1  christos 	}
    316  1.1  christos       /* See if --all is the last token in the input.  */
    317  1.1  christos       if (strcmp (chp, "--all") == 0)
    318  1.1  christos 	{
    319  1.1  christos           parse->all = 1;
    320  1.1  christos           chp += strlen (chp);
    321  1.1  christos         }
    322  1.1  christos       if (strncmp (chp, "--thread-group ", tgs) == 0)
    323  1.1  christos 	{
    324  1.1  christos 	  char *endp;
    325  1.1  christos 
    326  1.1  christos 	  option = "--thread-group";
    327  1.1  christos 	  if (parse->thread_group != -1)
    328  1.1  christos 	    error (_("Duplicate '--thread-group' option"));
    329  1.1  christos 	  chp += tgs;
    330  1.1  christos 	  if (*chp != 'i')
    331  1.1  christos 	    error (_("Invalid thread group id"));
    332  1.1  christos 	  chp += 1;
    333  1.1  christos 	  parse->thread_group = strtol (chp, &endp, 10);
    334  1.1  christos 	  chp = endp;
    335  1.1  christos 	}
    336  1.1  christos       else if (strncmp (chp, "--thread ", ts) == 0)
    337  1.1  christos 	{
    338  1.1  christos 	  char *endp;
    339  1.1  christos 
    340  1.1  christos 	  option = "--thread";
    341  1.1  christos 	  if (parse->thread != -1)
    342  1.1  christos 	    error (_("Duplicate '--thread' option"));
    343  1.1  christos 	  chp += ts;
    344  1.1  christos 	  parse->thread = strtol (chp, &endp, 10);
    345  1.1  christos 	  chp = endp;
    346  1.1  christos 	}
    347  1.1  christos       else if (strncmp (chp, "--frame ", fs) == 0)
    348  1.1  christos 	{
    349  1.1  christos 	  char *endp;
    350  1.1  christos 
    351  1.1  christos 	  option = "--frame";
    352  1.1  christos 	  if (parse->frame != -1)
    353  1.1  christos 	    error (_("Duplicate '--frame' option"));
    354  1.1  christos 	  chp += fs;
    355  1.1  christos 	  parse->frame = strtol (chp, &endp, 10);
    356  1.1  christos 	  chp = endp;
    357  1.1  christos 	}
    358  1.1  christos       else if (strncmp (chp, "--language ", ls) == 0)
    359  1.1  christos 	{
    360  1.1  christos 	  char *lang_name;
    361  1.1  christos 	  struct cleanup *old_chain;
    362  1.1  christos 
    363  1.1  christos 	  option = "--language";
    364  1.1  christos 	  chp += ls;
    365  1.1  christos 	  lang_name = extract_arg_const (&chp);
    366  1.1  christos 	  old_chain = make_cleanup (xfree, lang_name);
    367  1.1  christos 
    368  1.1  christos 	  parse->language = language_enum (lang_name);
    369  1.1  christos 	  if (parse->language == language_unknown
    370  1.1  christos 	      || parse->language == language_auto)
    371  1.1  christos 	    error (_("Invalid --language argument: %s"), lang_name);
    372  1.1  christos 
    373  1.1  christos 	  do_cleanups (old_chain);
    374  1.1  christos 	}
    375  1.1  christos       else
    376  1.1  christos 	break;
    377  1.1  christos 
    378  1.1  christos       if (*chp != '\0' && !isspace (*chp))
    379  1.1  christos 	error (_("Invalid value for the '%s' option"), option);
    380  1.1  christos       chp = skip_spaces_const (chp);
    381  1.1  christos     }
    382  1.1  christos 
    383  1.1  christos   /* For new argv commands, attempt to return the parsed argument
    384  1.1  christos      list.  */
    385  1.1  christos   if (parse->cmd->argv_func != NULL)
    386  1.1  christos     {
    387  1.1  christos       mi_parse_argv (chp, parse);
    388  1.1  christos       if (parse->argv == NULL)
    389  1.1  christos 	error (_("Problem parsing arguments: %s %s"), parse->command, chp);
    390  1.1  christos     }
    391  1.1  christos 
    392  1.1  christos   /* FIXME: DELETE THIS */
    393  1.1  christos   /* For CLI commands, also return the remainder of the
    394  1.1  christos      command line as a single string. */
    395  1.1  christos   if (parse->cmd->cli.cmd != NULL)
    396  1.1  christos     parse->args = xstrdup (chp);
    397  1.1  christos 
    398  1.1  christos   discard_cleanups (cleanup);
    399  1.1  christos 
    400  1.1  christos   /* Fully parsed, flag as an MI command.  */
    401  1.1  christos   parse->op = MI_COMMAND;
    402  1.1  christos   return parse;
    403  1.1  christos }
    404  1.1  christos 
    405  1.1  christos enum print_values
    406  1.1  christos mi_parse_print_values (const char *name)
    407  1.1  christos {
    408  1.1  christos    if (strcmp (name, "0") == 0
    409  1.1  christos        || strcmp (name, mi_no_values) == 0)
    410  1.1  christos      return PRINT_NO_VALUES;
    411  1.1  christos    else if (strcmp (name, "1") == 0
    412  1.1  christos 	    || strcmp (name, mi_all_values) == 0)
    413  1.1  christos      return PRINT_ALL_VALUES;
    414  1.1  christos    else if (strcmp (name, "2") == 0
    415  1.1  christos 	    || strcmp (name, mi_simple_values) == 0)
    416  1.1  christos      return PRINT_SIMPLE_VALUES;
    417  1.1  christos    else
    418  1.1  christos      error (_("Unknown value for PRINT_VALUES: must be: \
    419  1.1  christos 0 or \"%s\", 1 or \"%s\", 2 or \"%s\""),
    420  1.1  christos 	    mi_no_values, mi_all_values, mi_simple_values);
    421  1.1  christos }
    422