Upgrade GDB from 7.0 and 7.2 on the vendor branch
[dragonfly.git] / contrib / gdb-7 / 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
39   switch (c)
40     {
41       case '\n':
42         return -2;
43       case 0:
44         (*string_ptr)--;
45         return 0;
46
47       case '0':
48       case '1':
49       case '2':
50       case '3':
51       case '4':
52       case '5':
53       case '6':
54       case '7':
55         {
56           int i = host_hex_value (c);
57           int count = 0;
58
59           while (++count < 3)
60             {
61               c = (**string_ptr);
62               if (isdigit (c) && c != '8' && c != '9')
63                 {
64                   (*string_ptr)++;
65                   i *= 8;
66                   i += host_hex_value (c);
67                 }
68               else
69                 {
70                   break;
71                 }
72             }
73           return i;
74         }
75
76     case 'a':
77       c = '\a';
78       break;
79     case 'b':
80       c = '\b';
81       break;
82     case 'f':
83       c = '\f';
84       break;
85     case 'n':
86       c = '\n';
87       break;
88     case 'r':
89       c = '\r';
90       break;
91     case 't':
92       c = '\t';
93       break;
94     case 'v':
95       c = '\v';
96       break;
97
98     default:
99       break;
100     }
101
102   return c;
103 }
104
105 static void
106 mi_parse_argv (char *args, struct mi_parse *parse)
107 {
108   char *chp = args;
109   int argc = 0;
110   char **argv = xmalloc ((argc + 1) * sizeof (char *));
111
112   argv[argc] = NULL;
113   while (1)
114     {
115       char *arg;
116
117       /* skip leading white space */
118       while (isspace (*chp))
119         chp++;
120       /* Three possibilities: EOF, quoted string, or other text. */
121       switch (*chp)
122         {
123         case '\0':
124           parse->argv = argv;
125           parse->argc = argc;
126           return;
127         case '"':
128           {
129             /* A quoted string. */
130             int len;
131             char *start = chp + 1;
132
133             /* Determine the buffer size. */
134             chp = start;
135             len = 0;
136             while (*chp != '\0' && *chp != '"')
137               {
138                 if (*chp == '\\')
139                   {
140                     chp++;
141                     if (mi_parse_escape (&chp) <= 0)
142                       {
143                         /* Do not allow split lines or "\000" */
144                         freeargv (argv);
145                         return;
146                       }
147                   }
148                 else
149                   chp++;
150                 len++;
151               }
152             /* Insist on a closing quote. */
153             if (*chp != '"')
154               {
155                 freeargv (argv);
156                 return;
157               }
158             /* Insist on trailing white space. */
159             if (chp[1] != '\0' && !isspace (chp[1]))
160               {
161                 freeargv (argv);
162                 return;
163               }
164             /* create the buffer. */
165             arg = xmalloc ((len + 1) * sizeof (char));
166             /* And copy the characters in. */
167             chp = start;
168             len = 0;
169             while (*chp != '\0' && *chp != '"')
170               {
171                 if (*chp == '\\')
172                   {
173                     chp++;
174                     arg[len] = mi_parse_escape (&chp);
175                   }
176                 else
177                   arg[len] = *chp++;
178                 len++;
179               }
180             arg[len] = '\0';
181             chp++;              /* that closing quote. */
182             break;
183           }
184         default:
185           {
186             /* An unquoted string.  Accumulate all non blank
187                characters into a buffer. */
188             int len;
189             char *start = chp;
190
191             while (*chp != '\0' && !isspace (*chp))
192               {
193                 chp++;
194               }
195             len = chp - start;
196             arg = xmalloc ((len + 1) * sizeof (char));
197             strncpy (arg, start, len);
198             arg[len] = '\0';
199             break;
200           }
201         }
202       /* Append arg to argv. */
203       argv = xrealloc (argv, (argc + 2) * sizeof (char *));
204       argv[argc++] = arg;
205       argv[argc] = NULL;
206     }
207 }
208
209
210 void
211 mi_parse_free (struct mi_parse *parse)
212 {
213   if (parse == NULL)
214     return;
215   if (parse->command != NULL)
216     xfree (parse->command);
217   if (parse->token != NULL)
218     xfree (parse->token);
219   if (parse->args != NULL)
220     xfree (parse->args);
221   if (parse->argv != NULL)
222     freeargv (parse->argv);
223   xfree (parse);
224 }
225
226
227 struct mi_parse *
228 mi_parse (char *cmd)
229 {
230   char *chp;
231   struct mi_parse *parse = XMALLOC (struct mi_parse);
232
233   memset (parse, 0, sizeof (*parse));
234   parse->all = 0;
235   parse->thread_group = -1;
236   parse->thread = -1;
237   parse->frame = -1;
238
239   /* Before starting, skip leading white space. */
240   while (isspace (*cmd))
241     cmd++;
242
243   /* Find/skip any token and then extract it. */
244   for (chp = cmd; *chp >= '0' && *chp <= '9'; chp++)
245     ;
246   parse->token = xmalloc ((chp - cmd + 1) * sizeof (char *));
247   memcpy (parse->token, cmd, (chp - cmd));
248   parse->token[chp - cmd] = '\0';
249
250   /* This wasn't a real MI command.  Return it as a CLI_COMMAND. */
251   if (*chp != '-')
252     {
253       while (isspace (*chp))
254         chp++;
255       parse->command = xstrdup (chp);
256       parse->op = CLI_COMMAND;
257       return parse;
258     }
259
260   /* Extract the command. */
261   {
262     char *tmp = chp + 1;        /* discard ``-'' */
263
264     for (; *chp && !isspace (*chp); chp++)
265       ;
266     parse->command = xmalloc ((chp - tmp + 1) * sizeof (char *));
267     memcpy (parse->command, tmp, chp - tmp);
268     parse->command[chp - tmp] = '\0';
269   }
270
271   /* Find the command in the MI table. */
272   parse->cmd = mi_lookup (parse->command);
273   if (parse->cmd == NULL)
274     {
275       /* FIXME: This should be a function call. */
276       fprintf_unfiltered
277         (raw_stdout,
278          "%s^error,msg=\"Undefined MI command: %s\"\n",
279          parse->token, parse->command);
280       mi_parse_free (parse);
281       return NULL;
282     }
283
284   /* Skip white space following the command. */
285   while (isspace (*chp))
286     chp++;
287
288   /* Parse the --thread and --frame options, if present.  At present,
289      some important commands, like '-break-*' are implemented by forwarding
290      to the CLI layer directly.  We want to parse --thread and --frame
291      here, so as not to leave those option in the string that will be passed
292      to CLI.  */
293   for (;;)
294     {
295       char *start = chp;
296       size_t as = sizeof ("--all ") - 1;
297       size_t tgs = sizeof ("--thread-group ") - 1;
298       size_t ts = sizeof ("--thread ") - 1;
299       size_t fs = sizeof ("--frame ") - 1;
300
301       if (strncmp (chp, "--all ", as) == 0)
302         {
303           parse->all = 1;
304           chp += as;
305         }
306       /* See if --all is the last token in the input.  */
307       if (strcmp (chp, "--all") == 0)
308         {
309           parse->all = 1;
310           chp += strlen (chp);
311         }
312       if (strncmp (chp, "--thread-group ", tgs) == 0)
313         {
314           if (parse->thread_group != -1)
315             error (_("Duplicate '--thread-group' option"));
316           chp += tgs;
317           if (*chp != 'i')
318             error (_("Invalid thread group id"));
319           chp += 1;
320           parse->thread_group = strtol (chp, &chp, 10);
321         }
322       if (strncmp (chp, "--thread ", ts) == 0)
323         {
324           if (parse->thread != -1)
325             error (_("Duplicate '--thread' option"));
326           chp += ts;
327           parse->thread = strtol (chp, &chp, 10);
328         }
329       else if (strncmp (chp, "--frame ", fs) == 0)
330         {
331           if (parse->frame != -1)
332             error (_("Duplicate '--frame' option"));
333           chp += fs;
334           parse->frame = strtol (chp, &chp, 10);
335         }
336       else
337         break;
338
339       if (*chp != '\0' && !isspace (*chp))
340         error (_("Invalid value for the '%s' option"),
341                start[2] == 't' ? "--thread" : "--frame");
342       while (isspace (*chp))
343         chp++;
344     }
345
346   /* For new argv commands, attempt to return the parsed argument
347      list. */
348   if (parse->cmd->argv_func != NULL)
349     {
350       mi_parse_argv (chp, parse);
351       if (parse->argv == NULL)
352         {
353           /* FIXME: This should be a function call. */
354           fprintf_unfiltered
355             (raw_stdout,
356              "%s^error,msg=\"Problem parsing arguments: %s %s\"\n",
357              parse->token, parse->command, chp);
358           mi_parse_free (parse);
359           return NULL;
360         }
361     }
362
363   /* FIXME: DELETE THIS */
364   /* For CLI commands, also return the remainder of the
365      command line as a single string. */
366   if (parse->cmd->cli.cmd != NULL)
367     parse->args = xstrdup (chp);
368
369   /* Fully parsed. */
370   parse->op = MI_COMMAND;
371   return parse;
372 }