Initial import of binutils 2.22 on the new 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, 2011
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 /* A cleanup that calls mi_parse_free.  */
227
228 static void
229 mi_parse_cleanup (void *arg)
230 {
231   mi_parse_free (arg);
232 }
233
234 struct mi_parse *
235 mi_parse (char *cmd, char **token)
236 {
237   char *chp;
238   struct mi_parse *parse = XMALLOC (struct mi_parse);
239   struct cleanup *cleanup;
240
241   memset (parse, 0, sizeof (*parse));
242   parse->all = 0;
243   parse->thread_group = -1;
244   parse->thread = -1;
245   parse->frame = -1;
246
247   cleanup = make_cleanup (mi_parse_cleanup, parse);
248
249   /* Before starting, skip leading white space. */
250   while (isspace (*cmd))
251     cmd++;
252
253   /* Find/skip any token and then extract it. */
254   for (chp = cmd; *chp >= '0' && *chp <= '9'; chp++)
255     ;
256   *token = xmalloc ((chp - cmd + 1) * sizeof (char *));
257   memcpy (*token, cmd, (chp - cmd));
258   (*token)[chp - cmd] = '\0';
259
260   /* This wasn't a real MI command.  Return it as a CLI_COMMAND. */
261   if (*chp != '-')
262     {
263       while (isspace (*chp))
264         chp++;
265       parse->command = xstrdup (chp);
266       parse->op = CLI_COMMAND;
267
268       discard_cleanups (cleanup);
269
270       return parse;
271     }
272
273   /* Extract the command. */
274   {
275     char *tmp = chp + 1;        /* discard ``-'' */
276
277     for (; *chp && !isspace (*chp); chp++)
278       ;
279     parse->command = xmalloc ((chp - tmp + 1) * sizeof (char *));
280     memcpy (parse->command, tmp, chp - tmp);
281     parse->command[chp - tmp] = '\0';
282   }
283
284   /* Find the command in the MI table. */
285   parse->cmd = mi_lookup (parse->command);
286   if (parse->cmd == NULL)
287     error (_("Undefined MI command: %s"), parse->command);
288
289   /* Skip white space following the command. */
290   while (isspace (*chp))
291     chp++;
292
293   /* Parse the --thread and --frame options, if present.  At present,
294      some important commands, like '-break-*' are implemented by forwarding
295      to the CLI layer directly.  We want to parse --thread and --frame
296      here, so as not to leave those option in the string that will be passed
297      to CLI.  */
298   for (;;)
299     {
300       const char *option;
301       size_t as = sizeof ("--all ") - 1;
302       size_t tgs = sizeof ("--thread-group ") - 1;
303       size_t ts = sizeof ("--thread ") - 1;
304       size_t fs = sizeof ("--frame ") - 1;
305
306       if (strncmp (chp, "--all ", as) == 0)
307         {
308           parse->all = 1;
309           chp += as;
310         }
311       /* See if --all is the last token in the input.  */
312       if (strcmp (chp, "--all") == 0)
313         {
314           parse->all = 1;
315           chp += strlen (chp);
316         }
317       if (strncmp (chp, "--thread-group ", tgs) == 0)
318         {
319           option = "--thread-group";
320           if (parse->thread_group != -1)
321             error (_("Duplicate '--thread-group' option"));
322           chp += tgs;
323           if (*chp != 'i')
324             error (_("Invalid thread group id"));
325           chp += 1;
326           parse->thread_group = strtol (chp, &chp, 10);
327         }
328       else if (strncmp (chp, "--thread ", ts) == 0)
329         {
330           option = "--thread";
331           if (parse->thread != -1)
332             error (_("Duplicate '--thread' option"));
333           chp += ts;
334           parse->thread = strtol (chp, &chp, 10);
335         }
336       else if (strncmp (chp, "--frame ", fs) == 0)
337         {
338           option = "--frame";
339           if (parse->frame != -1)
340             error (_("Duplicate '--frame' option"));
341           chp += fs;
342           parse->frame = strtol (chp, &chp, 10);
343         }
344       else
345         break;
346
347       if (*chp != '\0' && !isspace (*chp))
348         error (_("Invalid value for the '%s' option"), option);
349       while (isspace (*chp))
350         chp++;
351     }
352
353   /* For new argv commands, attempt to return the parsed argument
354      list. */
355   if (parse->cmd->argv_func != NULL)
356     {
357       mi_parse_argv (chp, parse);
358       if (parse->argv == NULL)
359         error (_("Problem parsing arguments: %s %s"), parse->command, chp);
360     }
361
362   /* FIXME: DELETE THIS */
363   /* For CLI commands, also return the remainder of the
364      command line as a single string. */
365   if (parse->cmd->cli.cmd != NULL)
366     parse->args = xstrdup (chp);
367
368   discard_cleanups (cleanup);
369
370   /* Fully parsed. */
371   parse->op = MI_COMMAND;
372   return parse;
373 }