Upgrade GDB from 7.4.1 to 7.6.1 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-2013 Free Software Foundation, Inc.
4
5    Contributed by Cygnus Solutions (a Red Hat company).
6
7    This file is part of GDB.
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
21
22 #include "defs.h"
23 #include "mi-cmds.h"
24 #include "mi-parse.h"
25 #include "charset.h"
26
27 #include <ctype.h>
28 #include "gdb_string.h"
29 #include "cli/cli-utils.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 (const 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 (const char *args, struct mi_parse *parse)
107 {
108   const 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       chp = skip_spaces_const (chp);
119       /* Three possibilities: EOF, quoted string, or other text. */
120       switch (*chp)
121         {
122         case '\0':
123           parse->argv = argv;
124           parse->argc = argc;
125           return;
126         case '"':
127           {
128             /* A quoted string.  */
129             int len;
130             const char *start = chp + 1;
131
132             /* Determine the buffer size.  */
133             chp = start;
134             len = 0;
135             while (*chp != '\0' && *chp != '"')
136               {
137                 if (*chp == '\\')
138                   {
139                     chp++;
140                     if (mi_parse_escape (&chp) <= 0)
141                       {
142                         /* Do not allow split lines or "\000".  */
143                         freeargv (argv);
144                         return;
145                       }
146                   }
147                 else
148                   chp++;
149                 len++;
150               }
151             /* Insist on a closing quote.  */
152             if (*chp != '"')
153               {
154                 freeargv (argv);
155                 return;
156               }
157             /* Insist on trailing white space.  */
158             if (chp[1] != '\0' && !isspace (chp[1]))
159               {
160                 freeargv (argv);
161                 return;
162               }
163             /* Create the buffer and copy characters in.  */
164             arg = xmalloc ((len + 1) * sizeof (char));
165             chp = start;
166             len = 0;
167             while (*chp != '\0' && *chp != '"')
168               {
169                 if (*chp == '\\')
170                   {
171                     chp++;
172                     arg[len] = mi_parse_escape (&chp);
173                   }
174                 else
175                   arg[len] = *chp++;
176                 len++;
177               }
178             arg[len] = '\0';
179             chp++;              /* That closing quote.  */
180             break;
181           }
182         default:
183           {
184             /* An unquoted string.  Accumulate all non-blank
185                characters into a buffer.  */
186             int len;
187             const char *start = chp;
188
189             while (*chp != '\0' && !isspace (*chp))
190               {
191                 chp++;
192               }
193             len = chp - start;
194             arg = xmalloc ((len + 1) * sizeof (char));
195             strncpy (arg, start, len);
196             arg[len] = '\0';
197             break;
198           }
199         }
200       /* Append arg to argv.  */
201       argv = xrealloc (argv, (argc + 2) * sizeof (char *));
202       argv[argc++] = arg;
203       argv[argc] = NULL;
204     }
205 }
206
207 void
208 mi_parse_free (struct mi_parse *parse)
209 {
210   if (parse == NULL)
211     return;
212   if (parse->command != NULL)
213     xfree (parse->command);
214   if (parse->token != NULL)
215     xfree (parse->token);
216   if (parse->args != NULL)
217     xfree (parse->args);
218   if (parse->argv != NULL)
219     freeargv (parse->argv);
220   xfree (parse);
221 }
222
223 /* A cleanup that calls mi_parse_free.  */
224
225 static void
226 mi_parse_cleanup (void *arg)
227 {
228   mi_parse_free (arg);
229 }
230
231 struct mi_parse *
232 mi_parse (const char *cmd, char **token)
233 {
234   const char *chp;
235   struct mi_parse *parse = XMALLOC (struct mi_parse);
236   struct cleanup *cleanup;
237
238   memset (parse, 0, sizeof (*parse));
239   parse->all = 0;
240   parse->thread_group = -1;
241   parse->thread = -1;
242   parse->frame = -1;
243
244   cleanup = make_cleanup (mi_parse_cleanup, parse);
245
246   /* Before starting, skip leading white space.  */
247   cmd = skip_spaces_const (cmd);
248
249   /* Find/skip any token and then extract it.  */
250   for (chp = cmd; *chp >= '0' && *chp <= '9'; chp++)
251     ;
252   *token = xmalloc (chp - cmd + 1);
253   memcpy (*token, cmd, (chp - cmd));
254   (*token)[chp - cmd] = '\0';
255
256   /* This wasn't a real MI command.  Return it as a CLI_COMMAND.  */
257   if (*chp != '-')
258     {
259       chp = skip_spaces_const (chp);
260       parse->command = xstrdup (chp);
261       parse->op = CLI_COMMAND;
262
263       discard_cleanups (cleanup);
264
265       return parse;
266     }
267
268   /* Extract the command.  */
269   {
270     const char *tmp = chp + 1;  /* discard ``-'' */
271
272     for (; *chp && !isspace (*chp); chp++)
273       ;
274     parse->command = xmalloc (chp - tmp + 1);
275     memcpy (parse->command, tmp, chp - tmp);
276     parse->command[chp - tmp] = '\0';
277   }
278
279   /* Find the command in the MI table.  */
280   parse->cmd = mi_lookup (parse->command);
281   if (parse->cmd == NULL)
282     error (_("Undefined MI command: %s"), parse->command);
283
284   /* Skip white space following the command.  */
285   chp = skip_spaces_const (chp);
286
287   /* Parse the --thread and --frame options, if present.  At present,
288      some important commands, like '-break-*' are implemented by
289      forwarding to the CLI layer directly.  We want to parse --thread
290      and --frame here, so as not to leave those option in the string
291      that will be passed to CLI.  */
292   for (;;)
293     {
294       const char *option;
295       size_t as = sizeof ("--all ") - 1;
296       size_t tgs = sizeof ("--thread-group ") - 1;
297       size_t ts = sizeof ("--thread ") - 1;
298       size_t fs = sizeof ("--frame ") - 1;
299
300       if (strncmp (chp, "--all ", as) == 0)
301         {
302           parse->all = 1;
303           chp += as;
304         }
305       /* See if --all is the last token in the input.  */
306       if (strcmp (chp, "--all") == 0)
307         {
308           parse->all = 1;
309           chp += strlen (chp);
310         }
311       if (strncmp (chp, "--thread-group ", tgs) == 0)
312         {
313           char *endp;
314
315           option = "--thread-group";
316           if (parse->thread_group != -1)
317             error (_("Duplicate '--thread-group' option"));
318           chp += tgs;
319           if (*chp != 'i')
320             error (_("Invalid thread group id"));
321           chp += 1;
322           parse->thread_group = strtol (chp, &endp, 10);
323           chp = endp;
324         }
325       else if (strncmp (chp, "--thread ", ts) == 0)
326         {
327           char *endp;
328
329           option = "--thread";
330           if (parse->thread != -1)
331             error (_("Duplicate '--thread' option"));
332           chp += ts;
333           parse->thread = strtol (chp, &endp, 10);
334           chp = endp;
335         }
336       else if (strncmp (chp, "--frame ", fs) == 0)
337         {
338           char *endp;
339
340           option = "--frame";
341           if (parse->frame != -1)
342             error (_("Duplicate '--frame' option"));
343           chp += fs;
344           parse->frame = strtol (chp, &endp, 10);
345           chp = endp;
346         }
347       else
348         break;
349
350       if (*chp != '\0' && !isspace (*chp))
351         error (_("Invalid value for the '%s' option"), option);
352       chp = skip_spaces_const (chp);
353     }
354
355   /* For new argv commands, attempt to return the parsed argument
356      list.  */
357   if (parse->cmd->argv_func != NULL)
358     {
359       mi_parse_argv (chp, parse);
360       if (parse->argv == NULL)
361         error (_("Problem parsing arguments: %s %s"), parse->command, chp);
362     }
363
364   /* FIXME: DELETE THIS */
365   /* For CLI commands, also return the remainder of the
366      command line as a single string. */
367   if (parse->cmd->cli.cmd != NULL)
368     parse->args = xstrdup (chp);
369
370   discard_cleanups (cleanup);
371
372   /* Fully parsed, flag as an MI command.  */
373   parse->op = MI_COMMAND;
374   return parse;
375 }