gdb/mi/mi-parse.c - gdb

Global variables defined

Functions defined

Source code

  1. /* MI Command Set - MI parser.

  2.    Copyright (C) 2000-2015 Free Software Foundation, Inc.

  3.    Contributed by Cygnus Solutions (a Red Hat company).

  4.    This file is part of GDB.

  5.    This program is free software; you can redistribute it and/or modify
  6.    it under the terms of the GNU General Public License as published by
  7.    the Free Software Foundation; either version 3 of the License, or
  8.    (at your option) any later version.

  9.    This program is distributed in the hope that it will be useful,
  10.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.    GNU General Public License for more details.

  13.    You should have received a copy of the GNU General Public License
  14.    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */

  15. #include "defs.h"
  16. #include "mi-cmds.h"
  17. #include "mi-parse.h"
  18. #include "charset.h"

  19. #include <ctype.h>
  20. #include "cli/cli-utils.h"
  21. #include "language.h"

  22. static const char mi_no_values[] = "--no-values";
  23. static const char mi_simple_values[] = "--simple-values";
  24. static const char mi_all_values[] = "--all-values";

  25. /* Like parse_escape, but leave the results as a host char, not a
  26.    target char.  */

  27. static int
  28. mi_parse_escape (const char **string_ptr)
  29. {
  30.   int c = *(*string_ptr)++;

  31.   switch (c)
  32.     {
  33.       case '\n':
  34.         return -2;
  35.       case 0:
  36.         (*string_ptr)--;
  37.         return 0;

  38.       case '0':
  39.       case '1':
  40.       case '2':
  41.       case '3':
  42.       case '4':
  43.       case '5':
  44.       case '6':
  45.       case '7':
  46.         {
  47.           int i = host_hex_value (c);
  48.           int count = 0;

  49.           while (++count < 3)
  50.             {
  51.               c = (**string_ptr);
  52.               if (isdigit (c) && c != '8' && c != '9')
  53.                 {
  54.                   (*string_ptr)++;
  55.                   i *= 8;
  56.                   i += host_hex_value (c);
  57.                 }
  58.               else
  59.                 {
  60.                   break;
  61.                 }
  62.             }
  63.           return i;
  64.         }

  65.     case 'a':
  66.       c = '\a';
  67.       break;
  68.     case 'b':
  69.       c = '\b';
  70.       break;
  71.     case 'f':
  72.       c = '\f';
  73.       break;
  74.     case 'n':
  75.       c = '\n';
  76.       break;
  77.     case 'r':
  78.       c = '\r';
  79.       break;
  80.     case 't':
  81.       c = '\t';
  82.       break;
  83.     case 'v':
  84.       c = '\v';
  85.       break;

  86.     default:
  87.       break;
  88.     }

  89.   return c;
  90. }

  91. static void
  92. mi_parse_argv (const char *args, struct mi_parse *parse)
  93. {
  94.   const char *chp = args;
  95.   int argc = 0;
  96.   char **argv = xmalloc ((argc + 1) * sizeof (char *));

  97.   argv[argc] = NULL;
  98.   while (1)
  99.     {
  100.       char *arg;

  101.       /* Skip leading white space.  */
  102.       chp = skip_spaces_const (chp);
  103.       /* Three possibilities: EOF, quoted string, or other text. */
  104.       switch (*chp)
  105.         {
  106.         case '\0':
  107.           parse->argv = argv;
  108.           parse->argc = argc;
  109.           return;
  110.         case '"':
  111.           {
  112.             /* A quoted string.  */
  113.             int len;
  114.             const char *start = chp + 1;

  115.             /* Determine the buffer size.  */
  116.             chp = start;
  117.             len = 0;
  118.             while (*chp != '\0' && *chp != '"')
  119.               {
  120.                 if (*chp == '\\')
  121.                   {
  122.                     chp++;
  123.                     if (mi_parse_escape (&chp) <= 0)
  124.                       {
  125.                         /* Do not allow split lines or "\000".  */
  126.                         freeargv (argv);
  127.                         return;
  128.                       }
  129.                   }
  130.                 else
  131.                   chp++;
  132.                 len++;
  133.               }
  134.             /* Insist on a closing quote.  */
  135.             if (*chp != '"')
  136.               {
  137.                 freeargv (argv);
  138.                 return;
  139.               }
  140.             /* Insist on trailing white space.  */
  141.             if (chp[1] != '\0' && !isspace (chp[1]))
  142.               {
  143.                 freeargv (argv);
  144.                 return;
  145.               }
  146.             /* Create the buffer and copy characters in.  */
  147.             arg = xmalloc ((len + 1) * sizeof (char));
  148.             chp = start;
  149.             len = 0;
  150.             while (*chp != '\0' && *chp != '"')
  151.               {
  152.                 if (*chp == '\\')
  153.                   {
  154.                     chp++;
  155.                     arg[len] = mi_parse_escape (&chp);
  156.                   }
  157.                 else
  158.                   arg[len] = *chp++;
  159.                 len++;
  160.               }
  161.             arg[len] = '\0';
  162.             chp++;                /* That closing quote.  */
  163.             break;
  164.           }
  165.         default:
  166.           {
  167.             /* An unquoted string.  Accumulate all non-blank
  168.                characters into a buffer.  */
  169.             int len;
  170.             const char *start = chp;

  171.             while (*chp != '\0' && !isspace (*chp))
  172.               {
  173.                 chp++;
  174.               }
  175.             len = chp - start;
  176.             arg = xmalloc ((len + 1) * sizeof (char));
  177.             strncpy (arg, start, len);
  178.             arg[len] = '\0';
  179.             break;
  180.           }
  181.         }
  182.       /* Append arg to argv.  */
  183.       argv = xrealloc (argv, (argc + 2) * sizeof (char *));
  184.       argv[argc++] = arg;
  185.       argv[argc] = NULL;
  186.     }
  187. }

  188. void
  189. mi_parse_free (struct mi_parse *parse)
  190. {
  191.   if (parse == NULL)
  192.     return;
  193.   if (parse->command != NULL)
  194.     xfree (parse->command);
  195.   if (parse->token != NULL)
  196.     xfree (parse->token);
  197.   if (parse->args != NULL)
  198.     xfree (parse->args);
  199.   if (parse->argv != NULL)
  200.     freeargv (parse->argv);
  201.   xfree (parse);
  202. }

  203. /* A cleanup that calls mi_parse_free.  */

  204. static void
  205. mi_parse_cleanup (void *arg)
  206. {
  207.   mi_parse_free (arg);
  208. }

  209. struct mi_parse *
  210. mi_parse (const char *cmd, char **token)
  211. {
  212.   const char *chp;
  213.   struct mi_parse *parse = XNEW (struct mi_parse);
  214.   struct cleanup *cleanup;

  215.   memset (parse, 0, sizeof (*parse));
  216.   parse->all = 0;
  217.   parse->thread_group = -1;
  218.   parse->thread = -1;
  219.   parse->frame = -1;
  220.   parse->language = language_unknown;

  221.   cleanup = make_cleanup (mi_parse_cleanup, parse);

  222.   /* Before starting, skip leading white space.  */
  223.   cmd = skip_spaces_const (cmd);

  224.   /* Find/skip any token and then extract it.  */
  225.   for (chp = cmd; *chp >= '0' && *chp <= '9'; chp++)
  226.     ;
  227.   *token = xmalloc (chp - cmd + 1);
  228.   memcpy (*token, cmd, (chp - cmd));
  229.   (*token)[chp - cmd] = '\0';

  230.   /* This wasn't a real MI command.  Return it as a CLI_COMMAND.  */
  231.   if (*chp != '-')
  232.     {
  233.       chp = skip_spaces_const (chp);
  234.       parse->command = xstrdup (chp);
  235.       parse->op = CLI_COMMAND;

  236.       discard_cleanups (cleanup);

  237.       return parse;
  238.     }

  239.   /* Extract the command.  */
  240.   {
  241.     const char *tmp = chp + 1;        /* discard ``-'' */

  242.     for (; *chp && !isspace (*chp); chp++)
  243.       ;
  244.     parse->command = xmalloc (chp - tmp + 1);
  245.     memcpy (parse->command, tmp, chp - tmp);
  246.     parse->command[chp - tmp] = '\0';
  247.   }

  248.   /* Find the command in the MI table.  */
  249.   parse->cmd = mi_lookup (parse->command);
  250.   if (parse->cmd == NULL)
  251.     throw_error (UNDEFINED_COMMAND_ERROR,
  252.                  _("Undefined MI command: %s"), parse->command);

  253.   /* Skip white space following the command.  */
  254.   chp = skip_spaces_const (chp);

  255.   /* Parse the --thread and --frame options, if present.  At present,
  256.      some important commands, like '-break-*' are implemented by
  257.      forwarding to the CLI layer directly.  We want to parse --thread
  258.      and --frame here, so as not to leave those option in the string
  259.      that will be passed to CLI.

  260.      Same for the --language option.  */

  261.   for (;;)
  262.     {
  263.       const char *option;
  264.       size_t as = sizeof ("--all ") - 1;
  265.       size_t tgs = sizeof ("--thread-group ") - 1;
  266.       size_t ts = sizeof ("--thread ") - 1;
  267.       size_t fs = sizeof ("--frame ") - 1;
  268.       size_t ls = sizeof ("--language ") - 1;

  269.       if (strncmp (chp, "--all ", as) == 0)
  270.         {
  271.           parse->all = 1;
  272.           chp += as;
  273.         }
  274.       /* See if --all is the last token in the input.  */
  275.       if (strcmp (chp, "--all") == 0)
  276.         {
  277.           parse->all = 1;
  278.           chp += strlen (chp);
  279.         }
  280.       if (strncmp (chp, "--thread-group ", tgs) == 0)
  281.         {
  282.           char *endp;

  283.           option = "--thread-group";
  284.           if (parse->thread_group != -1)
  285.             error (_("Duplicate '--thread-group' option"));
  286.           chp += tgs;
  287.           if (*chp != 'i')
  288.             error (_("Invalid thread group id"));
  289.           chp += 1;
  290.           parse->thread_group = strtol (chp, &endp, 10);
  291.           chp = endp;
  292.         }
  293.       else if (strncmp (chp, "--thread ", ts) == 0)
  294.         {
  295.           char *endp;

  296.           option = "--thread";
  297.           if (parse->thread != -1)
  298.             error (_("Duplicate '--thread' option"));
  299.           chp += ts;
  300.           parse->thread = strtol (chp, &endp, 10);
  301.           chp = endp;
  302.         }
  303.       else if (strncmp (chp, "--frame ", fs) == 0)
  304.         {
  305.           char *endp;

  306.           option = "--frame";
  307.           if (parse->frame != -1)
  308.             error (_("Duplicate '--frame' option"));
  309.           chp += fs;
  310.           parse->frame = strtol (chp, &endp, 10);
  311.           chp = endp;
  312.         }
  313.       else if (strncmp (chp, "--language ", ls) == 0)
  314.         {
  315.           char *lang_name;
  316.           struct cleanup *old_chain;

  317.           option = "--language";
  318.           chp += ls;
  319.           lang_name = extract_arg_const (&chp);
  320.           old_chain = make_cleanup (xfree, lang_name);

  321.           parse->language = language_enum (lang_name);
  322.           if (parse->language == language_unknown
  323.               || parse->language == language_auto)
  324.             error (_("Invalid --language argument: %s"), lang_name);

  325.           do_cleanups (old_chain);
  326.         }
  327.       else
  328.         break;

  329.       if (*chp != '\0' && !isspace (*chp))
  330.         error (_("Invalid value for the '%s' option"), option);
  331.       chp = skip_spaces_const (chp);
  332.     }

  333.   /* For new argv commands, attempt to return the parsed argument
  334.      list.  */
  335.   if (parse->cmd->argv_func != NULL)
  336.     {
  337.       mi_parse_argv (chp, parse);
  338.       if (parse->argv == NULL)
  339.         error (_("Problem parsing arguments: %s %s"), parse->command, chp);
  340.     }

  341.   /* FIXME: DELETE THIS */
  342.   /* For CLI commands, also return the remainder of the
  343.      command line as a single string. */
  344.   if (parse->cmd->cli.cmd != NULL)
  345.     parse->args = xstrdup (chp);

  346.   discard_cleanups (cleanup);

  347.   /* Fully parsed, flag as an MI command.  */
  348.   parse->op = MI_COMMAND;
  349.   return parse;
  350. }

  351. enum print_values
  352. mi_parse_print_values (const char *name)
  353. {
  354.    if (strcmp (name, "0") == 0
  355.        || strcmp (name, mi_no_values) == 0)
  356.      return PRINT_NO_VALUES;
  357.    else if (strcmp (name, "1") == 0
  358.             || strcmp (name, mi_all_values) == 0)
  359.      return PRINT_ALL_VALUES;
  360.    else if (strcmp (name, "2") == 0
  361.             || strcmp (name, mi_simple_values) == 0)
  362.      return PRINT_SIMPLE_VALUES;
  363.    else
  364.      error (_("Unknown value for PRINT_VALUES: must be: \
  365. 0 or \"%s\", 1 or \"%s\", 2 or \"%s\""),
  366.             mi_no_values, mi_all_values, mi_simple_values);
  367. }