psymtab cleanup patch 3/3
[platform/upstream/binutils.git] / gdb / mi / mi-parse.c
1 /* MI Command Set - MI parser.
2
3    Copyright (C) 2000-2014 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 <string.h>
29 #include "cli/cli-utils.h"
30 #include "language.h"
31
32 static const char mi_no_values[] = "--no-values";
33 static const char mi_simple_values[] = "--simple-values";
34 static const char mi_all_values[] = "--all-values";
35
36 /* Like parse_escape, but leave the results as a host char, not a
37    target char.  */
38
39 static int
40 mi_parse_escape (const char **string_ptr)
41 {
42   int c = *(*string_ptr)++;
43
44   switch (c)
45     {
46       case '\n':
47         return -2;
48       case 0:
49         (*string_ptr)--;
50         return 0;
51
52       case '0':
53       case '1':
54       case '2':
55       case '3':
56       case '4':
57       case '5':
58       case '6':
59       case '7':
60         {
61           int i = host_hex_value (c);
62           int count = 0;
63
64           while (++count < 3)
65             {
66               c = (**string_ptr);
67               if (isdigit (c) && c != '8' && c != '9')
68                 {
69                   (*string_ptr)++;
70                   i *= 8;
71                   i += host_hex_value (c);
72                 }
73               else
74                 {
75                   break;
76                 }
77             }
78           return i;
79         }
80
81     case 'a':
82       c = '\a';
83       break;
84     case 'b':
85       c = '\b';
86       break;
87     case 'f':
88       c = '\f';
89       break;
90     case 'n':
91       c = '\n';
92       break;
93     case 'r':
94       c = '\r';
95       break;
96     case 't':
97       c = '\t';
98       break;
99     case 'v':
100       c = '\v';
101       break;
102
103     default:
104       break;
105     }
106
107   return c;
108 }
109
110 static void
111 mi_parse_argv (const char *args, struct mi_parse *parse)
112 {
113   const char *chp = args;
114   int argc = 0;
115   char **argv = xmalloc ((argc + 1) * sizeof (char *));
116
117   argv[argc] = NULL;
118   while (1)
119     {
120       char *arg;
121
122       /* Skip leading white space.  */
123       chp = skip_spaces_const (chp);
124       /* Three possibilities: EOF, quoted string, or other text. */
125       switch (*chp)
126         {
127         case '\0':
128           parse->argv = argv;
129           parse->argc = argc;
130           return;
131         case '"':
132           {
133             /* A quoted string.  */
134             int len;
135             const char *start = chp + 1;
136
137             /* Determine the buffer size.  */
138             chp = start;
139             len = 0;
140             while (*chp != '\0' && *chp != '"')
141               {
142                 if (*chp == '\\')
143                   {
144                     chp++;
145                     if (mi_parse_escape (&chp) <= 0)
146                       {
147                         /* Do not allow split lines or "\000".  */
148                         freeargv (argv);
149                         return;
150                       }
151                   }
152                 else
153                   chp++;
154                 len++;
155               }
156             /* Insist on a closing quote.  */
157             if (*chp != '"')
158               {
159                 freeargv (argv);
160                 return;
161               }
162             /* Insist on trailing white space.  */
163             if (chp[1] != '\0' && !isspace (chp[1]))
164               {
165                 freeargv (argv);
166                 return;
167               }
168             /* Create the buffer and copy characters in.  */
169             arg = xmalloc ((len + 1) * sizeof (char));
170             chp = start;
171             len = 0;
172             while (*chp != '\0' && *chp != '"')
173               {
174                 if (*chp == '\\')
175                   {
176                     chp++;
177                     arg[len] = mi_parse_escape (&chp);
178                   }
179                 else
180                   arg[len] = *chp++;
181                 len++;
182               }
183             arg[len] = '\0';
184             chp++;              /* That closing quote.  */
185             break;
186           }
187         default:
188           {
189             /* An unquoted string.  Accumulate all non-blank
190                characters into a buffer.  */
191             int len;
192             const char *start = chp;
193
194             while (*chp != '\0' && !isspace (*chp))
195               {
196                 chp++;
197               }
198             len = chp - start;
199             arg = xmalloc ((len + 1) * sizeof (char));
200             strncpy (arg, start, len);
201             arg[len] = '\0';
202             break;
203           }
204         }
205       /* Append arg to argv.  */
206       argv = xrealloc (argv, (argc + 2) * sizeof (char *));
207       argv[argc++] = arg;
208       argv[argc] = NULL;
209     }
210 }
211
212 void
213 mi_parse_free (struct mi_parse *parse)
214 {
215   if (parse == NULL)
216     return;
217   if (parse->command != NULL)
218     xfree (parse->command);
219   if (parse->token != NULL)
220     xfree (parse->token);
221   if (parse->args != NULL)
222     xfree (parse->args);
223   if (parse->argv != NULL)
224     freeargv (parse->argv);
225   xfree (parse);
226 }
227
228 /* A cleanup that calls mi_parse_free.  */
229
230 static void
231 mi_parse_cleanup (void *arg)
232 {
233   mi_parse_free (arg);
234 }
235
236 struct mi_parse *
237 mi_parse (const char *cmd, char **token)
238 {
239   const char *chp;
240   struct mi_parse *parse = XNEW (struct mi_parse);
241   struct cleanup *cleanup;
242
243   memset (parse, 0, sizeof (*parse));
244   parse->all = 0;
245   parse->thread_group = -1;
246   parse->thread = -1;
247   parse->frame = -1;
248   parse->language = language_unknown;
249
250   cleanup = make_cleanup (mi_parse_cleanup, parse);
251
252   /* Before starting, skip leading white space.  */
253   cmd = skip_spaces_const (cmd);
254
255   /* Find/skip any token and then extract it.  */
256   for (chp = cmd; *chp >= '0' && *chp <= '9'; chp++)
257     ;
258   *token = xmalloc (chp - cmd + 1);
259   memcpy (*token, cmd, (chp - cmd));
260   (*token)[chp - cmd] = '\0';
261
262   /* This wasn't a real MI command.  Return it as a CLI_COMMAND.  */
263   if (*chp != '-')
264     {
265       chp = skip_spaces_const (chp);
266       parse->command = xstrdup (chp);
267       parse->op = CLI_COMMAND;
268
269       discard_cleanups (cleanup);
270
271       return parse;
272     }
273
274   /* Extract the command.  */
275   {
276     const char *tmp = chp + 1;  /* discard ``-'' */
277
278     for (; *chp && !isspace (*chp); chp++)
279       ;
280     parse->command = xmalloc (chp - tmp + 1);
281     memcpy (parse->command, tmp, chp - tmp);
282     parse->command[chp - tmp] = '\0';
283   }
284
285   /* Find the command in the MI table.  */
286   parse->cmd = mi_lookup (parse->command);
287   if (parse->cmd == NULL)
288     throw_error (UNDEFINED_COMMAND_ERROR,
289                  _("Undefined MI command: %s"), parse->command);
290
291   /* Skip white space following the command.  */
292   chp = skip_spaces_const (chp);
293
294   /* Parse the --thread and --frame options, if present.  At present,
295      some important commands, like '-break-*' are implemented by
296      forwarding to the CLI layer directly.  We want to parse --thread
297      and --frame here, so as not to leave those option in the string
298      that will be passed to CLI.
299
300      Same for the --language option.  */
301
302   for (;;)
303     {
304       const char *option;
305       size_t as = sizeof ("--all ") - 1;
306       size_t tgs = sizeof ("--thread-group ") - 1;
307       size_t ts = sizeof ("--thread ") - 1;
308       size_t fs = sizeof ("--frame ") - 1;
309       size_t ls = sizeof ("--language ") - 1;
310
311       if (strncmp (chp, "--all ", as) == 0)
312         {
313           parse->all = 1;
314           chp += as;
315         }
316       /* See if --all is the last token in the input.  */
317       if (strcmp (chp, "--all") == 0)
318         {
319           parse->all = 1;
320           chp += strlen (chp);
321         }
322       if (strncmp (chp, "--thread-group ", tgs) == 0)
323         {
324           char *endp;
325
326           option = "--thread-group";
327           if (parse->thread_group != -1)
328             error (_("Duplicate '--thread-group' option"));
329           chp += tgs;
330           if (*chp != 'i')
331             error (_("Invalid thread group id"));
332           chp += 1;
333           parse->thread_group = strtol (chp, &endp, 10);
334           chp = endp;
335         }
336       else if (strncmp (chp, "--thread ", ts) == 0)
337         {
338           char *endp;
339
340           option = "--thread";
341           if (parse->thread != -1)
342             error (_("Duplicate '--thread' option"));
343           chp += ts;
344           parse->thread = strtol (chp, &endp, 10);
345           chp = endp;
346         }
347       else if (strncmp (chp, "--frame ", fs) == 0)
348         {
349           char *endp;
350
351           option = "--frame";
352           if (parse->frame != -1)
353             error (_("Duplicate '--frame' option"));
354           chp += fs;
355           parse->frame = strtol (chp, &endp, 10);
356           chp = endp;
357         }
358       else if (strncmp (chp, "--language ", ls) == 0)
359         {
360           char *lang_name;
361           struct cleanup *old_chain;
362
363           option = "--language";
364           chp += ls;
365           lang_name = extract_arg_const (&chp);
366           old_chain = make_cleanup (xfree, lang_name);
367
368           parse->language = language_enum (lang_name);
369           if (parse->language == language_unknown
370               || parse->language == language_auto)
371             error (_("Invalid --language argument: %s"), lang_name);
372
373           do_cleanups (old_chain);
374         }
375       else
376         break;
377
378       if (*chp != '\0' && !isspace (*chp))
379         error (_("Invalid value for the '%s' option"), option);
380       chp = skip_spaces_const (chp);
381     }
382
383   /* For new argv commands, attempt to return the parsed argument
384      list.  */
385   if (parse->cmd->argv_func != NULL)
386     {
387       mi_parse_argv (chp, parse);
388       if (parse->argv == NULL)
389         error (_("Problem parsing arguments: %s %s"), parse->command, chp);
390     }
391
392   /* FIXME: DELETE THIS */
393   /* For CLI commands, also return the remainder of the
394      command line as a single string. */
395   if (parse->cmd->cli.cmd != NULL)
396     parse->args = xstrdup (chp);
397
398   discard_cleanups (cleanup);
399
400   /* Fully parsed, flag as an MI command.  */
401   parse->op = MI_COMMAND;
402   return parse;
403 }
404
405 enum print_values
406 mi_parse_print_values (const char *name)
407 {
408    if (strcmp (name, "0") == 0
409        || strcmp (name, mi_no_values) == 0)
410      return PRINT_NO_VALUES;
411    else if (strcmp (name, "1") == 0
412             || strcmp (name, mi_all_values) == 0)
413      return PRINT_ALL_VALUES;
414    else if (strcmp (name, "2") == 0
415             || strcmp (name, mi_simple_values) == 0)
416      return PRINT_SIMPLE_VALUES;
417    else
418      error (_("Unknown value for PRINT_VALUES: must be: \
419 0 or \"%s\", 1 or \"%s\", 2 or \"%s\""),
420             mi_no_values, mi_all_values, mi_simple_values);
421 }