GDB (API)
/home/stan/gdb/src/gdb/mi/mi-parse.c
Go to the documentation of this file.
00001 /* MI Command Set - MI parser.
00002 
00003    Copyright (C) 2000-2013 Free Software Foundation, Inc.
00004 
00005    Contributed by Cygnus Solutions (a Red Hat company).
00006 
00007    This file is part of GDB.
00008 
00009    This program is free software; you can redistribute it and/or modify
00010    it under the terms of the GNU General Public License as published by
00011    the Free Software Foundation; either version 3 of the License, or
00012    (at your option) any later version.
00013 
00014    This program is distributed in the hope that it will be useful,
00015    but WITHOUT ANY WARRANTY; without even the implied warranty of
00016    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017    GNU General Public License for more details.
00018 
00019    You should have received a copy of the GNU General Public License
00020    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
00021 
00022 #include "defs.h"
00023 #include "mi-cmds.h"
00024 #include "mi-parse.h"
00025 #include "charset.h"
00026 
00027 #include <ctype.h>
00028 #include "gdb_string.h"
00029 #include "cli/cli-utils.h"
00030 
00031 static const char mi_no_values[] = "--no-values";
00032 static const char mi_simple_values[] = "--simple-values";
00033 static const char mi_all_values[] = "--all-values";
00034 
00035 /* Like parse_escape, but leave the results as a host char, not a
00036    target char.  */
00037 
00038 static int
00039 mi_parse_escape (const char **string_ptr)
00040 {
00041   int c = *(*string_ptr)++;
00042 
00043   switch (c)
00044     {
00045       case '\n':
00046         return -2;
00047       case 0:
00048         (*string_ptr)--;
00049         return 0;
00050 
00051       case '0':
00052       case '1':
00053       case '2':
00054       case '3':
00055       case '4':
00056       case '5':
00057       case '6':
00058       case '7':
00059         {
00060           int i = host_hex_value (c);
00061           int count = 0;
00062 
00063           while (++count < 3)
00064             {
00065               c = (**string_ptr);
00066               if (isdigit (c) && c != '8' && c != '9')
00067                 {
00068                   (*string_ptr)++;
00069                   i *= 8;
00070                   i += host_hex_value (c);
00071                 }
00072               else
00073                 {
00074                   break;
00075                 }
00076             }
00077           return i;
00078         }
00079 
00080     case 'a':
00081       c = '\a';
00082       break;
00083     case 'b':
00084       c = '\b';
00085       break;
00086     case 'f':
00087       c = '\f';
00088       break;
00089     case 'n':
00090       c = '\n';
00091       break;
00092     case 'r':
00093       c = '\r';
00094       break;
00095     case 't':
00096       c = '\t';
00097       break;
00098     case 'v':
00099       c = '\v';
00100       break;
00101 
00102     default:
00103       break;
00104     }
00105 
00106   return c;
00107 }
00108 
00109 static void
00110 mi_parse_argv (const char *args, struct mi_parse *parse)
00111 {
00112   const char *chp = args;
00113   int argc = 0;
00114   char **argv = xmalloc ((argc + 1) * sizeof (char *));
00115 
00116   argv[argc] = NULL;
00117   while (1)
00118     {
00119       char *arg;
00120 
00121       /* Skip leading white space.  */
00122       chp = skip_spaces_const (chp);
00123       /* Three possibilities: EOF, quoted string, or other text. */
00124       switch (*chp)
00125         {
00126         case '\0':
00127           parse->argv = argv;
00128           parse->argc = argc;
00129           return;
00130         case '"':
00131           {
00132             /* A quoted string.  */
00133             int len;
00134             const char *start = chp + 1;
00135 
00136             /* Determine the buffer size.  */
00137             chp = start;
00138             len = 0;
00139             while (*chp != '\0' && *chp != '"')
00140               {
00141                 if (*chp == '\\')
00142                   {
00143                     chp++;
00144                     if (mi_parse_escape (&chp) <= 0)
00145                       {
00146                         /* Do not allow split lines or "\000".  */
00147                         freeargv (argv);
00148                         return;
00149                       }
00150                   }
00151                 else
00152                   chp++;
00153                 len++;
00154               }
00155             /* Insist on a closing quote.  */
00156             if (*chp != '"')
00157               {
00158                 freeargv (argv);
00159                 return;
00160               }
00161             /* Insist on trailing white space.  */
00162             if (chp[1] != '\0' && !isspace (chp[1]))
00163               {
00164                 freeargv (argv);
00165                 return;
00166               }
00167             /* Create the buffer and copy characters in.  */
00168             arg = xmalloc ((len + 1) * sizeof (char));
00169             chp = start;
00170             len = 0;
00171             while (*chp != '\0' && *chp != '"')
00172               {
00173                 if (*chp == '\\')
00174                   {
00175                     chp++;
00176                     arg[len] = mi_parse_escape (&chp);
00177                   }
00178                 else
00179                   arg[len] = *chp++;
00180                 len++;
00181               }
00182             arg[len] = '\0';
00183             chp++;              /* That closing quote.  */
00184             break;
00185           }
00186         default:
00187           {
00188             /* An unquoted string.  Accumulate all non-blank
00189                characters into a buffer.  */
00190             int len;
00191             const char *start = chp;
00192 
00193             while (*chp != '\0' && !isspace (*chp))
00194               {
00195                 chp++;
00196               }
00197             len = chp - start;
00198             arg = xmalloc ((len + 1) * sizeof (char));
00199             strncpy (arg, start, len);
00200             arg[len] = '\0';
00201             break;
00202           }
00203         }
00204       /* Append arg to argv.  */
00205       argv = xrealloc (argv, (argc + 2) * sizeof (char *));
00206       argv[argc++] = arg;
00207       argv[argc] = NULL;
00208     }
00209 }
00210 
00211 void
00212 mi_parse_free (struct mi_parse *parse)
00213 {
00214   if (parse == NULL)
00215     return;
00216   if (parse->command != NULL)
00217     xfree (parse->command);
00218   if (parse->token != NULL)
00219     xfree (parse->token);
00220   if (parse->args != NULL)
00221     xfree (parse->args);
00222   if (parse->argv != NULL)
00223     freeargv (parse->argv);
00224   xfree (parse);
00225 }
00226 
00227 /* A cleanup that calls mi_parse_free.  */
00228 
00229 static void
00230 mi_parse_cleanup (void *arg)
00231 {
00232   mi_parse_free (arg);
00233 }
00234 
00235 struct mi_parse *
00236 mi_parse (const char *cmd, char **token)
00237 {
00238   const char *chp;
00239   struct mi_parse *parse = XMALLOC (struct mi_parse);
00240   struct cleanup *cleanup;
00241 
00242   memset (parse, 0, sizeof (*parse));
00243   parse->all = 0;
00244   parse->thread_group = -1;
00245   parse->thread = -1;
00246   parse->frame = -1;
00247 
00248   cleanup = make_cleanup (mi_parse_cleanup, parse);
00249 
00250   /* Before starting, skip leading white space.  */
00251   cmd = skip_spaces_const (cmd);
00252 
00253   /* Find/skip any token and then extract it.  */
00254   for (chp = cmd; *chp >= '0' && *chp <= '9'; chp++)
00255     ;
00256   *token = xmalloc (chp - cmd + 1);
00257   memcpy (*token, cmd, (chp - cmd));
00258   (*token)[chp - cmd] = '\0';
00259 
00260   /* This wasn't a real MI command.  Return it as a CLI_COMMAND.  */
00261   if (*chp != '-')
00262     {
00263       chp = skip_spaces_const (chp);
00264       parse->command = xstrdup (chp);
00265       parse->op = CLI_COMMAND;
00266 
00267       discard_cleanups (cleanup);
00268 
00269       return parse;
00270     }
00271 
00272   /* Extract the command.  */
00273   {
00274     const char *tmp = chp + 1;  /* discard ``-'' */
00275 
00276     for (; *chp && !isspace (*chp); chp++)
00277       ;
00278     parse->command = xmalloc (chp - tmp + 1);
00279     memcpy (parse->command, tmp, chp - tmp);
00280     parse->command[chp - tmp] = '\0';
00281   }
00282 
00283   /* Find the command in the MI table.  */
00284   parse->cmd = mi_lookup (parse->command);
00285   if (parse->cmd == NULL)
00286     error (_("Undefined MI command: %s"), parse->command);
00287 
00288   /* Skip white space following the command.  */
00289   chp = skip_spaces_const (chp);
00290 
00291   /* Parse the --thread and --frame options, if present.  At present,
00292      some important commands, like '-break-*' are implemented by
00293      forwarding to the CLI layer directly.  We want to parse --thread
00294      and --frame here, so as not to leave those option in the string
00295      that will be passed to CLI.  */
00296   for (;;)
00297     {
00298       const char *option;
00299       size_t as = sizeof ("--all ") - 1;
00300       size_t tgs = sizeof ("--thread-group ") - 1;
00301       size_t ts = sizeof ("--thread ") - 1;
00302       size_t fs = sizeof ("--frame ") - 1;
00303 
00304       if (strncmp (chp, "--all ", as) == 0)
00305         {
00306           parse->all = 1;
00307           chp += as;
00308         }
00309       /* See if --all is the last token in the input.  */
00310       if (strcmp (chp, "--all") == 0)
00311         {
00312           parse->all = 1;
00313           chp += strlen (chp);
00314         }
00315       if (strncmp (chp, "--thread-group ", tgs) == 0)
00316         {
00317           char *endp;
00318 
00319           option = "--thread-group";
00320           if (parse->thread_group != -1)
00321             error (_("Duplicate '--thread-group' option"));
00322           chp += tgs;
00323           if (*chp != 'i')
00324             error (_("Invalid thread group id"));
00325           chp += 1;
00326           parse->thread_group = strtol (chp, &endp, 10);
00327           chp = endp;
00328         }
00329       else if (strncmp (chp, "--thread ", ts) == 0)
00330         {
00331           char *endp;
00332 
00333           option = "--thread";
00334           if (parse->thread != -1)
00335             error (_("Duplicate '--thread' option"));
00336           chp += ts;
00337           parse->thread = strtol (chp, &endp, 10);
00338           chp = endp;
00339         }
00340       else if (strncmp (chp, "--frame ", fs) == 0)
00341         {
00342           char *endp;
00343 
00344           option = "--frame";
00345           if (parse->frame != -1)
00346             error (_("Duplicate '--frame' option"));
00347           chp += fs;
00348           parse->frame = strtol (chp, &endp, 10);
00349           chp = endp;
00350         }
00351       else
00352         break;
00353 
00354       if (*chp != '\0' && !isspace (*chp))
00355         error (_("Invalid value for the '%s' option"), option);
00356       chp = skip_spaces_const (chp);
00357     }
00358 
00359   /* For new argv commands, attempt to return the parsed argument
00360      list.  */
00361   if (parse->cmd->argv_func != NULL)
00362     {
00363       mi_parse_argv (chp, parse);
00364       if (parse->argv == NULL)
00365         error (_("Problem parsing arguments: %s %s"), parse->command, chp);
00366     }
00367 
00368   /* FIXME: DELETE THIS */
00369   /* For CLI commands, also return the remainder of the
00370      command line as a single string. */
00371   if (parse->cmd->cli.cmd != NULL)
00372     parse->args = xstrdup (chp);
00373 
00374   discard_cleanups (cleanup);
00375 
00376   /* Fully parsed, flag as an MI command.  */
00377   parse->op = MI_COMMAND;
00378   return parse;
00379 }
00380 
00381 enum print_values
00382 mi_parse_print_values (const char *name)
00383 {
00384    if (strcmp (name, "0") == 0
00385        || strcmp (name, mi_no_values) == 0)
00386      return PRINT_NO_VALUES;
00387    else if (strcmp (name, "1") == 0
00388             || strcmp (name, mi_all_values) == 0)
00389      return PRINT_ALL_VALUES;
00390    else if (strcmp (name, "2") == 0
00391             || strcmp (name, mi_simple_values) == 0)
00392      return PRINT_SIMPLE_VALUES;
00393    else
00394      error (_("Unknown value for PRINT_VALUES: must be: \
00395 0 or \"%s\", 1 or \"%s\", 2 or \"%s\""),
00396             mi_no_values, mi_all_values, mi_simple_values);
00397 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines