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